SpringBoot 配置文件敏感信息加密:从 Jasypt 到生产级 Secret 管理

欢迎你来读这篇博客,这篇博客主要是关于 SpringBoot 配置文件敏感信息加密

其中包括了关于我的见解和收集的知识分享:为什么配置文件里不能直接放数据库密码、API Key、Redis 密码;Jasypt 如何解决“密文存储、启动解密”的问题;以及在微服务、配置中心、Kubernetes、Vault 等生产环境里,应该如何更稳妥地管理敏感配置。

序言

在 Spring Boot 项目里,application.ymlapplication.properties 通常会保存很多运行配置,例如数据库连接、Redis 地址、MQ 账号、第三方 API Key、短信平台密钥、对象存储密钥等。

开发阶段图方便,很多人会这么写:

1
2
3
4
5
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: 123456

这当然能跑,但问题也很明显:一旦代码提交到 Git、被打包进镜像、发到测试环境、上传到制品库,密码就会跟着到处裸奔。配置文件不是保险柜,把密码写进去,最多只能算“给小偷整理好了目录”。

所以,配置敏感信息的安全处理,至少要回答三个问题:

  1. 敏感信息是否应该出现在代码仓库里?
  2. 如果必须放在配置文件里,能否以密文形式保存?
  3. 解密密钥、访问凭证、轮换机制应该由谁来管理?

这篇文章从 Spring Boot 常见场景出发,重点讲 Jasypt 的配置加密方案,同时也会补充配置中心、Kubernetes Secret、Vault、云厂商 Secret Manager 等更适合生产环境的方案。

正文

chapter 1:Spring Boot 配置为什么容易泄露敏感信息?

Spring Boot 的配置系统非常灵活。它可以从很多地方读取配置,例如:

  • application.yml
  • application.properties
  • application-dev.yml
  • 环境变量
  • JVM 系统属性
  • 命令行参数
  • 外部配置目录
  • 配置中心
  • Kubernetes Secret / ConfigMap
  • Vault / Secret Manager

灵活是好事,但灵活也意味着风险更分散。

常见泄露场景包括:

  1. 配置文件提交到 Git

    开发人员把数据库密码、Redis 密码、第三方平台密钥直接写在 application.yml,然后提交到仓库。即便后面删掉,Git 历史里也可能还在。

  2. 打包进 Jar 或镜像

    如果生产密码写在项目资源目录里,它会被一起打进 Jar 包或 Docker 镜像。只要有人拿到制品,就有机会解压看到配置。

  3. 日志误打印

    有些项目启动时会打印配置对象,或者异常堆栈里带出连接串,敏感信息可能直接进入日志系统。

  4. 配置中心权限过大

    微服务项目常用 Nacos、Apollo、Spring Cloud Config 等配置中心。如果所有开发、测试、运维人员都能看到生产配置,那配置中心就变成了“密码公告栏”。

  5. 密钥和密文放在一起

    有人把配置值加密了,但又把解密密钥也写在同一个 application.yml。这就像门上挂了把锁,然后把钥匙贴在门框上。形式上安全,实际上很尴尬。

所以,配置安全的第一原则是:

明文敏感信息不要进入代码仓库,解密密钥不要和密文放在同一个地方。

chapter 2:Jasypt 是什么?

Jasypt,全称 Java Simplified Encryption,是 Java 生态里常用的加解密工具。结合 jasypt-spring-boot-starter 后,它可以让 Spring Boot 在读取配置属性时自动识别密文,并在注入到 Spring Environment 前完成解密。

典型效果是这样:

1
2
3
4
spring:
datasource:
username: ENC(加密后的用户名)
password: ENC(加密后的密码)

应用启动时,Jasypt 会识别 ENC(...),用指定的解密密钥把里面的密文解开,最终业务代码拿到的仍然是正常的明文值。

也就是说,代码里依旧可以这样使用:

1
2
@Value("${spring.datasource.password}")
private String password;

或者:

1
2
3
4
5
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String username;
private String password;
}

业务代码无需关心加解密过程。

这就是 Jasypt 的核心价值:

配置文件里存密文,应用启动时自动解密,业务代码无感知。

chapter 3:Spring Boot 集成 Jasypt

以 Maven 项目为例,先引入依赖。

1
2
3
4
5
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>4.0.4</version>
</dependency>

然后在配置文件里设置加密算法和密文识别规则:

1
2
3
4
5
6
7
jasypt:
encryptor:
algorithm: PBEWITHHMACSHA512ANDAES_256
iv-generator-classname: org.jasypt.iv.RandomIvGenerator
property:
prefix: ENC(
suffix: )

注意,这里故意没有写:

1
2
3
jasypt:
encryptor:
password: xxx

因为 jasypt.encryptor.password 是解密密钥,不能和密文一起放在配置文件中。

更推荐通过环境变量、JVM 参数或启动参数传入:

1
java -jar app.jar --jasypt.encryptor.password=your-secret-key

或者:

1
2
export JASYPT_ENCRYPTOR_PASSWORD=your-secret-key
java -jar app.jar

在 Docker 或 Kubernetes 环境里,也可以通过 Secret 注入环境变量。

chapter 4:如何生成密文?

Jasypt 常见有两种方式生成密文。

方式一:写测试类生成密文

可以注入 StringEncryptor

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootTest
class JasyptEncryptTest {

@Autowired
private StringEncryptor stringEncryptor;

@Test
void encrypt() {
System.out.println(stringEncryptor.encrypt("root"));
System.out.println(stringEncryptor.encrypt("123456"));
System.out.println(stringEncryptor.encrypt("jdbc:mysql://localhost:3306/demo"));
}
}

然后将输出结果放进配置文件:

1
2
3
4
5
spring:
datasource:
url: ENC(xxx)
username: ENC(xxx)
password: ENC(xxx)

这种方式简单,但容易把明文、密文、测试代码混在项目里。临时验证可以,长期使用不优雅。

方式二:使用 jasypt-maven-plugin

可以在 pom.xml 中加入插件:

1
2
3
4
5
6
7
8
9
<build>
<plugins>
<plugin>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-maven-plugin</artifactId>
<version>4.0.4</version>
</plugin>
</plugins>
</build>

先在配置文件中用 DEC(...) 包住待加密值:

1
2
spring.datasource.username=DEC(root)
spring.datasource.password=DEC(123456)

执行:

1
mvn jasypt:encrypt -Djasypt.encryptor.password="your-secret-key"

插件会把 DEC(...) 转换成 ENC(...)

1
2
spring.datasource.username=ENC(encrypted-username)
spring.datasource.password=ENC(encrypted-password)

如果只想加密单个值,可以执行:

1
2
3
mvn jasypt:encrypt-value \
-Djasypt.encryptor.password="your-secret-key" \
-Djasypt.plugin.value="123456"

这个方式更适合工程化使用。

chapter 5:Jasypt 的关键安全点

Jasypt 很好用,但别把它当成“万能保险箱”。它解决的是“配置文件密文存储”的问题,不解决所有 Secret 管理问题。

1. 密文可以提交,密钥不能提交

这是底线。

可以提交:

1
2
3
spring:
datasource:
password: ENC(xxxxxx)

不要提交:

1
2
3
jasypt:
encryptor:
password: your-secret-key

密文和密钥一旦放在一起,加密就失去了意义。

2. 不同环境使用不同密钥

开发、测试、预发、生产环境应该使用不同的加密密钥。

不要所有环境共用一个 jasypt.encryptor.password。否则测试环境泄露,生产环境也跟着裸奔。

建议:

1
2
3
4
5
6
7
8
# dev
JASYPT_ENCRYPTOR_PASSWORD=dev-key

# test
JASYPT_ENCRYPTOR_PASSWORD=test-key

# prod
JASYPT_ENCRYPTOR_PASSWORD=prod-key

3. 不要在日志中打印敏感配置

尤其是:

  • 数据库密码
  • Redis 密码
  • MQ 密码
  • Token
  • SecretKey
  • AccessKey
  • RefreshToken
  • 私钥内容

建议对配置对象的 toString() 做脱敏,或者禁止敏感字段打印。

示例:

1
2
3
4
5
6
private String mask(String value) {
if (value == null || value.length() <= 4) {
return "****";
}
return value.substring(0, 2) + "****" + value.substring(value.length() - 2);
}

日志里宁可少一点,也别把公司数据库密码“直播”出去。

4. 注意 Actuator 暴露风险

Spring Boot Actuator 的 /env/configprops 等端点可能暴露配置信息。生产环境要谨慎开放。

建议:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: health,info,prometheus

不要随手暴露所有端点:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: "*"

这属于“门开着,狗还帮你摇尾巴迎客”。

5. 定期轮换密钥

加密密钥不是祖传玉玺,不能一用十年。

一旦人员离职、仓库泄露、CI/CD 变量泄露、配置中心权限异常,都应该考虑轮换密钥。

Jasypt 轮换密钥的一般思路是:

  1. 用旧密钥解密旧配置。
  2. 用新密钥重新加密配置。
  3. 更新部署环境中的解密密钥。
  4. 重启或滚动发布服务。
  5. 删除旧密钥。

chapter 6:Jasypt 适合什么场景?

Jasypt 适合以下场景:

  1. 单体 Spring Boot 应用

    项目不复杂,配置主要在 application.yml 中,使用 Jasypt 可以快速避免明文密码入库。

  2. 中小型后台系统

    没有复杂的 Secret 管理平台,但又不希望配置中心或 Git 仓库里直接出现明文密码。

  3. 遗留系统改造

    老项目里已经有大量配置文件,短期内无法接入 Vault 或云厂商 Secret Manager,可以先用 Jasypt 做一层改造。

  4. 本地开发和测试环境

    对安全有要求,但暂时不想引入完整的密钥管理基础设施。

但如果是更复杂的生产系统,尤其是微服务、多环境、多租户、多团队协作,就不能只依赖 Jasypt。

chapter 7:配置中心场景应该怎么做?

在微服务体系里,配置常常放在 Nacos、Apollo、Spring Cloud Config 等配置中心。

这时要区分两个问题:

  1. 配置中心里是否允许存明文?
  2. 应用启动后如何拿到明文?

如果使用 Spring Cloud Config,它本身支持 {cipher} 形式的加密配置。配置仓库中可以保存:

1
2
3
spring:
datasource:
password: "{cipher}加密后的内容"

Config Server 读取后会先解密,再把明文配置发给客户端。

它的好处是:

  • Git 仓库里不是明文。
  • 加解密集中在 Config Server。
  • 客户端不需要每个服务都维护解密逻辑。

但是也要注意:

  • Config Server 的加密密钥必须保护好。
  • /encrypt/decrypt 端点必须加认证和访问控制。
  • 不要让所有人都能调用解密接口。
  • 配置中心和配置仓库权限要分级。

如果使用 Nacos 或 Apollo,常见做法有两种:

第一种是配置中心保存 Jasypt 密文,应用侧用 Jasypt 解密。

1
2
3
spring:
datasource:
password: ENC(xxxxxx)

第二种是配置中心或平台侧提供加密插件、密文管理、权限控制。

实际落地时,我更推荐按照团队成熟度选择:

  • 小团队:Jasypt + 环境变量密钥。
  • 中型团队:配置中心 + Jasypt + 权限隔离。
  • 大型团队:配置中心只放非敏感配置,敏感信息交给 Vault、KMS、Secret Manager。

chapter 8:Kubernetes 场景:Secret 不是终点

在 Kubernetes 中,可以使用 Secret 保存密码、Token、证书等敏感数据。

例如:

1
2
3
kubectl create secret generic db-secret \
--from-literal=username=root \
--from-literal=password=123456

然后在 Deployment 中注入环境变量:

1
2
3
4
5
6
7
8
9
10
11
env:
- name: SPRING_DATASOURCE_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password

Spring Boot 可以自动把环境变量绑定到配置项:

1
2
3
4
spring:
datasource:
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}

也可以把 Secret 挂载为文件,然后通过 Spring Boot 的 configtree: 读取。

例如:

1
2
3
spring:
config:
import: optional:configtree:/etc/secrets/

这种方式适合 Docker Secret、Kubernetes Secret Volume 等场景。

不过要注意,Kubernetes Secret 默认并不等于绝对安全。它更像是 Kubernetes 原生的敏感信息承载对象,而不是完整的密钥管理系统。生产环境至少要考虑:

  • etcd 加密存储。
  • RBAC 最小权限。
  • 禁止无关 Pod 读取 Secret。
  • 限制 namespace 权限。
  • 尽量通过 Volume 挂载而不是 API 读取。
  • 高安全场景接入外部 Secret Store。

chapter 9:Vault / Secret Manager:更生产级的方案

当系统规模变大后,Jasypt 的短板会越来越明显:

  • 密钥轮换麻烦。
  • 谁能解密不容易审计。
  • 密钥生命周期不够清晰。
  • 多服务、多环境、多团队管理复杂。
  • 无法很好支持动态凭证。

这时可以考虑使用:

  • HashiCorp Vault
  • AWS Secrets Manager
  • Azure Key Vault
  • Google Secret Manager
  • 阿里云 KMS / 凭据管家
  • 腾讯云 KMS / 凭据管理

以 Vault 为例,Spring Cloud Vault 可以通过 spring.config.import 引入 Vault 中的配置:

1
2
3
4
5
spring:
application:
name: order-service
config:
import: vault://

这样应用启动时会从 Vault 拉取配置,敏感信息不需要写进 application.yml

Vault 这类工具的核心价值不是“把字符串加密一下”,而是完整的 Secret 生命周期管理:

  • 集中存储。
  • 权限控制。
  • 审计日志。
  • 动态凭证。
  • 自动续租。
  • 密钥轮换。
  • 凭证吊销。

如果项目已经上云,云厂商 Secret Manager 也很适合。比如 AWS Secrets Manager 可以保存数据库账号、API Key 等,并支持自动轮换和按需读取。

chapter 10:不同方案怎么选?

可以按复杂度分层选择。

1. 个人项目 / 小型后台

推荐:

1
环境变量 + application.yml 占位符

示例:

1
2
3
4
spring:
datasource:
username: ${DB_USERNAME}
password: ${DB_PASSWORD}

优点是简单、直接、不引入额外依赖。

2. 已经有明文配置的老项目

推荐:

1
Jasypt

改造成本低,业务代码基本无感知。

3. 使用配置中心的微服务

推荐:

1
配置中心 + Jasypt / Spring Cloud Config 加密能力

重点是做好配置中心权限隔离,不要让所有人都能看生产配置。

4. Kubernetes 部署

推荐:

1
Kubernetes Secret + RBAC + etcd 加密 + Volume 挂载

如果安全要求更高,可以接入 External Secrets Operator 或 Secret Store CSI Driver。

5. 金融、支付、SaaS 多租户、强合规系统

推荐:

1
Vault / KMS / Secret Manager

这种场景不要只靠 Jasypt。Jasypt 是工具,不是治理体系。

chapter 11:一个推荐落地方案

如果现在有一个普通 Spring Boot / Spring Cloud 项目,我会这样落地:

本地开发环境

.env 或本机环境变量保存敏感信息,不提交 Git。

1
2
export DB_USERNAME=root
export DB_PASSWORD=123456

配置文件:

1
2
3
4
spring:
datasource:
username: ${DB_USERNAME}
password: ${DB_PASSWORD}

测试环境

配置中心保存 Jasypt 密文:

1
2
3
spring:
datasource:
password: ENC(xxxxxx)

解密密钥通过启动参数或环境变量注入:

1
JASYPT_ENCRYPTOR_PASSWORD=test-secret-key

生产环境

优先使用 Secret Manager / Vault / Kubernetes Secret。

如果短期只能用 Jasypt,则至少做到:

  • 生产密钥只在部署平台配置。
  • 生产密钥不进入 Git。
  • 生产密钥不出现在日志。
  • 生产配置中心权限严格隔离。
  • 定期轮换数据库密码和加密密钥。
  • CI/CD 平台的变量权限单独控制。
  • Actuator 端点只暴露必要能力。

chapter 12:常见误区

误区一:配置加密后就绝对安全

不是。

配置加密只解决“静态配置文件不存明文”的问题。应用运行时最终还是要拿到明文,否则它无法连接数据库、Redis、MQ。

所以真正的重点是:

  • 谁能拿到密文?
  • 谁能拿到密钥?
  • 谁能触发解密?
  • 解密过程有没有审计?
  • 密钥能不能轮换?

误区二:把 Jasypt 密钥写在 application.yml

这等于没加密。

错误示例:

1
2
3
4
5
6
7
spring:
datasource:
password: ENC(xxxxxx)

jasypt:
encryptor:
password: prod-secret-key

正确方向:

1
java -jar app.jar --jasypt.encryptor.password=prod-secret-key

或者使用部署平台注入环境变量。

误区三:所有敏感信息都用同一个密钥

不建议。

至少应该区分环境。更进一步,可以按业务域、系统等级、租户隔离策略拆分密钥。

误区四:配置中心权限随便给

配置中心是微服务时代的“中枢神经”。如果生产配置人人可见,那加密、认证、网关、审计都可能被绕开。

配置中心权限建议分层:

  • 开发人员:可看开发环境。
  • 测试人员:可看测试环境。
  • 运维人员:可管理部署变量。
  • 生产敏感配置:最小化授权。
  • 解密密钥:只给部署平台或密钥管理系统。

误区五:忽略历史提交

如果明文密码曾经提交过 Git,只删除当前文件是不够的。

要做的是:

  1. 立即更换已泄露密码。
  2. 清理 Git 历史或更换仓库访问权限。
  3. 检查 CI/CD、制品库、镜像仓库。
  4. 检查日志系统是否记录过明文。
  5. 增加 Git secret 扫描。

chapter 13:实践清单

最后给一份检查清单。

代码仓库

  • 不提交明文密码。
  • 不提交 .env
  • 不提交私钥文件。
  • 不提交生产配置。
  • 添加 .gitignore
  • 接入 secret scanning。

配置文件

  • 敏感字段使用占位符或密文。
  • 不在配置文件里写解密密钥。
  • 不在默认 profile 里放生产配置。
  • 不同环境配置隔离。

启动部署

  • 密钥通过环境变量、启动参数、Secret Volume 或密钥管理平台注入。
  • CI/CD 变量做权限控制。
  • 生产环境禁止打印完整启动参数。
  • 容器镜像不内置生产密钥。

应用运行

  • 日志脱敏。
  • Actuator 最小暴露。
  • 配置中心访问控制。
  • 数据库账号最小权限。
  • 定期轮换密码和密钥。

应急处理

  • 发现泄露后第一时间换密钥。
  • 不要只删配置文件。
  • 检查 Git 历史、日志、镜像、制品、配置中心。
  • 复盘权限链路。

参考资料

  • SpringBoot3:轻松使用 Jasypt 实现配置文件信息加密
  • Spring Boot Reference Documentation:Externalized Configuration
  • ulisesbocchio / jasypt-spring-boot 官方 README
  • Spring Cloud Config:Encryption and Decryption
  • Spring Cloud Config:Key Management
  • Spring Cloud Kubernetes:Secrets PropertySource
  • Kubernetes Documentation:Secrets
  • Spring Cloud Vault Reference Documentation
  • AWS Secrets Manager Documentation

启示录

配置加密这件事,表面看是“把密码加密一下”,本质上是“谁在什么时候,以什么权限,拿到什么秘密”。

Jasypt 是一个很好用的工具,尤其适合 Spring Boot 项目快速改造。但到了生产环境,真正可靠的方案一定不只是加密字符串,而是权限、审计、轮换、隔离、应急响应一起做。

安全不是把门锁上这么简单,还要知道钥匙在谁手里、谁配过钥匙、钥匙丢了怎么办。

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


SpringBoot 配置文件敏感信息加密:从 Jasypt 到生产级 Secret 管理
https://allendericdalexander.github.io/2026/06/01/spring_configuration_secret/
作者
AtLuoFu
发布于
2026年6月1日
许可协议