在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加密以零侵入、高效、易维护的优势,成为企业生产环境的首选;自定义加密工具类则以高灵活性,满足特殊场景的需求。
无论选择哪种方案,都需注意密钥的安全管理——密钥是加密的核心,必须避免与密文同文件存储,优先采用启动命令传参、系统环境变量等外置方式,结合服务器权限管控,才能真正实现敏感信息的全链路安全防护,杜绝因配置泄露导致的安全风险。