SpringBoot配置文件敏感信息加密:两种企业级实战方案

3 阅读9分钟

在SpringBoot项目开发中,配置文件(application.yml/application.properties) 会存储大量项目配置,其中数据库密码、Redis密码、第三方服务密钥、JWT签名密钥等敏感信息,若以明文形式存储,存在极高的安全风险——一旦配置文件泄露,核心信息会直接暴露,可能导致数据泄露、服务被攻击等严重问题。因此,生产环境中,配置文件敏感信息的加密处理是必不可少的环节。本文将详解两种企业级主流加密方案,覆盖轻量无侵入和高安全定制场景,附完整实操步骤和代码,可直接落地使用。

一、先明确:哪些敏感信息必须加密?

加密并非一刀切,需先界定加密边界,避免无效加密或遗漏关键信息,结合日常开发场景,以下几类信息必须加密:

  • 数据库相关信息:数据库连接密码、数据库登录账号,这类信息直接关联核心业务数据,泄露后果最严重;
  • 中间件密码:Redis、MongoDB、RabbitMQ等中间件的登录密码,尤其是集群环境的访问密码;
  • 第三方服务密钥:支付平台秘钥、OSS存储密钥、短信/邮件平台API密钥、第三方接口调用密钥;
  • 加密相关密钥:JWT签名密钥、对称/非对称加密的私钥、加密盐值等。

无需加密的配置:服务端口、日志级别、环境标识(dev/test/prod)、接口基础路径、数据库连接URL(不含账号密码)等非敏感信息,无需加密,避免增加开发和维护成本。

二、方案一:Jasypt加密(企业首选,零侵入高效落地)

Jasypt是SpringBoot生态中最常用的配置加密工具,也是大多数企业的首选方案。它的核心优势的是零代码侵入、自动化解密,只需简单三步配置,就能完成敏感信息加密,业务层完全无感,完美适配SpringBoot 2.x/3.x所有版本。

1. 核心优势

  • 零代码侵入:无需修改任何业务代码,仅需配置依赖、生成密文、替换配置,即可完成加密;
  • 自动化解密:项目启动时,Jasypt会自动识别密文格式,解密后注入到配置中,业务层获取配置的方式不变;
  • 多环境适配:开发、测试、生产可配置不同加密密钥,灵活切换,互不影响;
  • 安全可控:支持密钥外置,避免密钥与密文同文件存储,降低泄露风险,满足等保要求。

2. 完整实操步骤

步骤1:引入Jasypt核心依赖

使用Maven引入依赖(推荐稳定版本,适配SpringBoot所有版本),Gradle用户可对应调整依赖格式:

<!-- SpringBoot整合Jasypt加密依赖 -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
    

步骤2:生成明文对应的密文

Jasypt采用对称加密方式,需先通过「明文+自定义加密密钥」生成密文,推荐两种常用生成方式,可根据场景选择。

方式1:命令行生成(最快,无需写代码)

先下载jasypt-1.9.3.jar包(可从Maven仓库获取),放在本地任意目录,打开终端,进入该目录,执行以下命令,替换明文和加密密钥即可生成密文:

 
# 核心命令格式
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="明文内容" password="自定义加密密钥" algorithm=PBEWithMD5AndDES

# 实操示例:明文为数据库密码123456,加密密钥为boot_encrypt_2026(自定义,建议复杂)
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="123456" password="boot_encrypt_2026" algorithm=PBEWithMD5AndDES
    

执行后,终端会输出密文(复制OUTPUT后的内容即可),示例输出:


----ENVIRONMENT-----------------
Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.381-b09

----ARGUMENTS-------------------
algorithm: PBEWithMD5AndDES
input: 123456
password: boot_encrypt_2026

----OUTPUT----------------------
x7Z9c3V5b7N1m3K5p7O9q1R3T5y7U9i1O3P5
    
方式2:代码生成(项目内集成,适合开发调试)

若不想使用命令行,可在项目中编写工具类,生成密文,同时可验证解密效果,灵活可控:


import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;

/**
 * Jasypt加密工具类,用于生成密文、验证解密
 */
public class JasyptEncryptTool {
    public static void main(String[] args) {
        // 1. 创建加密器实例
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        // 2. 配置加密密钥(需与后续配置文件中的密钥一致)
        encryptor.setPassword("boot_encrypt_2026");
        // 3. 配置加密算法(固定使用PBEWithMD5AndDES,兼容所有版本)
        encryptor.setAlgorithm("PBEWithMD5AndDES");
        
        // 4. 加密明文(示例:加密Redis密码654321)
        String redisPwdPlain = "654321";
        String redisPwdCipher = encryptor.encrypt(redisPwdPlain);
        System.out.println("Redis密码密文:" + redisPwdCipher);
        
        // 5. 解密验证(可选,确保密文可正常解密)
        String redisPwdDecrypt = encryptor.decrypt(redisPwdCipher);
        System.out.println("Redis密码明文:" + redisPwdDecrypt);
    }
}
    

运行main方法,即可输出密文和解密后的明文,确保加密和解密正常。

步骤3:改造配置文件,替换敏感信息

Jasypt的核心规则:仅识别格式为「ENC(密文)」的内容(ENC必须大写),会自动解密该内容,直接替换配置文件中的明文即可,以主流的yml配置文件为例:


# 1. 配置Jasypt加密相关信息(核心)
jasypt:
  encryptor:
    password: boot_encrypt_2026  # 加密/解密密钥,与生成密文时一致
    algorithm: PBEWithMD5AndDES  # 加密算法,固定不变

# 2. 敏感信息用ENC(密文)替换明文(核心改造)
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/boot_db?useSSL=false&serverTimezone=UTC
    username: ENC(k2J4L6P8O0I9U7Y5T3G1B7N9M1K3J5L7P9O1) # 数据库账号密文
    password: ENC(x7Z9c3V5b7N1m3K5p7O9q1R3T5y7U9i1O3P5) # 数据库密码密文
  redis:
    host: localhost
    port: 6379
    password: ENC(a1S3D5F7G9H1J3L5P7O9Q1W3E5R7T9Y1U3I) # Redis密码密文
    

若使用properties配置文件,格式如下:


# Jasypt加密配置
jasypt.encryptor.password=boot_encrypt_2026
jasypt.encryptor.algorithm=PBEWithMD5AndDES

# 敏感信息加密
spring.datasource.username=ENC(k2J4L6P8O0I9U7Y5T3G1B7N9M1K3J5L7P9O1)
spring.datasource.password=ENC(x7Z9c3V5b7N1m3K5p7O9q1R3T5y7U9i1O3P5)
spring.redis.password=ENC(a1S3D5F7G9H1J3L5P7O9Q1W3E5R7T9Y1U3I)
    

步骤4:启动验证,业务层无感使用

配置完成后,直接启动SpringBoot项目,Jasypt会在项目启动时自动解密ENC()中的密文,注入到对应的配置属性中,业务层获取配置的方式完全不变,无需任何修改:


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConfigTestController {
    // 直接注入,获取的是Jasypt解密后的明文
    @Value("${spring.datasource.password}")
    private String dbPassword;
    
    @Value("${spring.redis.password}")
    private String redisPassword;
    
    @GetMapping("/test/config")
    public String testConfig() {
        return "数据库密码(解密后):" + dbPassword + "Redis密码(解密后):" + redisPassword;
    }
}
    

启动项目后,访问接口,会正常输出解密后的明文,说明加密和解密生效,业务层完全无需关注加密逻辑。

3. 生产级安全优化(关键避坑)

核心风险点:若将加密密钥(jasypt.encryptor.password)直接写在配置文件中,一旦配置文件泄露,密文可被轻易解密,这是开发中常见的低级错误。正确的做法是将密钥外置,脱离配置文件,推荐两种主流方式:

方式1:启动命令传参(生产首选,最安全)

删除配置文件中的jasypt.encryptor.password配置,启动项目时通过-D参数传入密钥,示例:


# jar包部署(生产标准方式)
java -jar springboot-encrypt-demo.jar -Djasypt.encryptor.password=boot_encrypt_2026

# IDE开发调试(VM options中配置)
-Djasypt.encryptor.password=boot_encrypt_2026
    

方式2:系统环境变量配置(适合集群部署)

在服务器中配置系统环境变量,Jasypt会自动读取环境变量中的密钥,配置文件中通过占位符引用,示例:


# Linux服务器配置环境变量(永久生效)
echo "export JASYPT_PASSWORD=boot_encrypt_2026" >> /etc/profile
source /etc/profile
    

配置文件中引用环境变量:


jasypt:
  encryptor:
    password: ${JASYPT_PASSWORD}  # 读取系统环境变量中的密钥
    algorithm: PBEWithMD5AndDES
    

三、方案二:自定义加密工具类(高安全场景,灵活定制)

若项目有特殊要求,比如禁止引入第三方依赖、需要使用自定义加密算法(如国密SM4、RSA非对称加密),则适合使用自定义加密工具类方案。该方案的核心是手写加密工具,手动完成密文生成和解密,灵活性极高,但存在一定的代码侵入性。

1. 适用场景

  • 项目有合规要求,禁止引入第三方加密依赖;
  • 对加密算法有特殊需求,需使用国密、RSA等自定义算法;
  • 极简项目,无需自动化解密,可接受少量代码开发。

2. 完整实操(AES加密示例)

以常用的AES对称加密为例,手写加密工具类,完成敏感信息加密和解密,步骤清晰可直接复用。

步骤1:手写AES加密工具类


import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

/**
 * 自定义AES加密工具类,实现明文与密文的互转
 */
public class AESencryptUtil {
    // 加密密钥(AES要求密钥长度为16位、24位或32位,自定义)
    private static final String AES_KEY = "boot_aes_key_2026";
    // 加密算法(固定,AES/ECB/PKCS5Padding兼容所有环境)
    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";

    /**
     * 加密:明文 → 密文(Base64编码,便于存储)
     */
    public static String encrypt(String plainText) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encryptBytes = cipher.doFinal(plainText.getBytes());
        // Base64编码,避免密文出现特殊字符,便于写入配置文件
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * 解密:密文 → 明文
     */
    public static String decrypt(String cipherText) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        // 先Base64解码,再解密
        byte[] decryptBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(decryptBytes);
    }

    // 测试加密和解密效果
    public static void main(String[] args) throws Exception {
        String plain = "db@123456"; // 明文(数据库密码)
        String cipher = encrypt(plain);
        System.out.println("AES加密后密文:" + cipher);
        System.out.println("AES解密后明文:" + decrypt(cipher));
    }
}
    

步骤2:配置文件写入密文

自定义加密无固定密文格式,直接将工具类生成的密文写入配置文件即可,无需添加额外标识:


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/boot_db?useSSL=false&serverTimezone=UTC
    username: 8z2X5C7v9B1n3M5s7K9p1Q3R5t7Y9u1I3O5P7  # 数据库账号密文
    password: 9m3K5p7O9q1R3T5y7U9i1O3P5Q7R9S1T3U5V7  # 数据库密码密文
    

步骤3:业务层手动解密使用

自定义加密无法实现自动化解密,需在业务层读取密文后,调用工具类手动解密,示例:


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

/**
 * 数据源配置类,手动解密敏感信息
 */
@Component
public class DataSourceConfig {
    // 读取配置文件中的密文
    @Value("${spring.datasource.username}")
    private String dbUsernameCipher;
    @Value("${spring.datasource.password}")
    private String dbPasswordCipher;

    // 解密后的明文,供业务层使用
    private String dbUsernamePlain;
    private String dbPasswordPlain;

    // 项目启动时执行解密(@PostConstruct注解确保启动时初始化)
    @PostConstruct
    public void decryptConfig() throws Exception {
        dbUsernamePlain = AESencryptUtil.decrypt(dbUsernameCipher);
        dbPasswordPlain = AESencryptUtil.decrypt(dbPasswordCipher);
    }

    // 提供获取明文的方法,供业务层调用
    public String getDbUsername() {
        return dbUsernamePlain;
    }

    public String getDbPassword() {
        return dbPasswordPlain;
    }
}
    

业务层调用时,直接获取解密后的明文即可,示例:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DataSourceTestController {
    @Autowired
    private DataSourceConfig dataSourceConfig;

    @GetMapping("/test/db")
    public String testDbConfig() {
        String username = dataSourceConfig.getDbUsername();
        String password = dataSourceConfig.getDbPassword();
        return "数据库账号:" + username + "数据库密码:" + password;
    }
}
    

四、两种方案对比与选型建议

实际开发中,需根据项目需求选择合适的加密方案,以下对比清晰呈现两种方案的差异,帮助快速选型:

对比维度Jasypt加密(方案一)自定义加密工具类(方案二)
代码侵入性零侵入,业务层无感强侵入,需手动解密
开发效率极高,三步即可完成配置较低,需手写加密工具和解密逻辑
加密灵活性固定算法,灵活度一般可自定义算法,灵活度极高
生产落地率广泛使用,适合绝大多数项目小众场景,仅适合特殊合规要求
维护成本低,无需额外维护高,需维护加密工具类

选型原则:无特殊合规或算法要求,优先选择Jasypt加密,兼顾开发效率和安全性;若有自定义算法、禁止第三方依赖等特殊需求,再选择自定义加密工具类方案。

五、核心总结

SpringBoot配置文件敏感信息加密的核心目标是「脱敏存储、安全可控」,两种方案各有适配场景:Jasypt加密以零侵入、高效、易维护的优势,成为企业生产环境的首选;自定义加密工具类则以高灵活性,满足特殊场景的需求。

无论选择哪种方案,都需注意密钥的安全管理——密钥是加密的核心,必须避免与密文同文件存储,优先采用启动命令传参、系统环境变量等外置方式,结合服务器权限管控,才能真正实现敏感信息的全链路安全防护,杜绝因配置泄露导致的安全风险。