Spring Boot 应用中构建配置文件敏感信息加密解密方案

news/2025/10/5 15:36:48/文章来源:https://www.cnblogs.com/slgkaifa/p/19126625

Spring Boot 应用中构建配置文件敏感信息加密解密方案


背景与挑战 ?

在现代企业级应用中,application.ymlapplication.properties 常用于配置数据库(DataSource)、Redis、RabbitMQ 等中间件的连接信息。

spring:
datasource:
username: myuser
password: my-secret-password

但问题来了:

将明文密码直接写入配置文件中存在诸多风险,主要包括:

❌ 风险类型详细描述
代码仓库泄露风险配置文件可能被误提交到 Git 等版本管理系统,导致敏感信息外泄。
构建与发布风险打包过程或日志文件可能暴露敏感数据,带来安全隐患。
调试与共享风险第三方人员或调试时可能接触到明文,增加信息暴露概率。

因此,敏感信息必须避免以明文形式存储。

一、设计目标 ?

目标说明
? 零明文配置配置文件中敏感字段均以 ENC(...) 形式存储,无明文密码。
⚙️ 自动解密应用启动时自动解密,业务代码无感知,无需改动。
? 多算法支持兼容 RSA、AES 等主流加密算法,满足不同安全需求。
?️ 开关灵活支持配置及环境变量动态启停解密功能,满足多环境多场景。
? 无侵入业务代码保持 Spring Boot 原生配置机制,业务层透明使用解密后的配置。

二、整体启动流程 ?

  1. 密钥注入

    通过环境变量(如 DB_SECRET_KEY)注入 RSA 私钥或对称密钥。

  2. EnvironmentPostProcessor 扫描

    Spring Boot 启动时自动加载实现了 EnvironmentPostProcessor 的解密组件。

  3. 配置源扫描

    遍历所有 PropertySource,查找形如 ENC(...) 的密文字段。

  4. 调用解密工具

    根据配置的算法(RSA/AES)还原明文。

  5. 注入环境变量

    将解密后的结果以 MapPropertySource 形式优先加载,覆盖原加密值。

  6. 后续加载

    DataSource、Redis、RabbitMQ 等配置自动获得解密后的明文。

在这里插入图片描述

三、方案实现详解 ⚙️

3.1 配置解密入口:EnvironmentPostProcessor

利用 Spring Boot 启动机制的 EnvironmentPostProcessor,启动早期扫描并解密所有配置文件中的敏感字段。

@Slf4j
public
class DecryptEnvPostProcessor
implements EnvironmentPostProcessor {
// 预定义需要解密的配置项 key,只对这些 key 进行解密处理
private
static
final Set<
String> ENCRYPTED_KEYS = Set.of(
"spring.datasource.password"
,
"custom.service.password"
)
;
@Override
public
void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
boolean enabled = Boolean.parseBoolean(env.getProperty("config.decrypt.enabled"
, "true"
)
)
;
if (!enabled) {
log.info("配置解密功能已关闭,跳过解密流程"
)
;
return
;
}
String key = System.getenv("DB_SECRET_KEY"
)
;
if (StringUtils.isBlank(key)
) {
throw
new IllegalStateException("缺少解密密钥(DB_SECRET_KEY),无法完成解密"
)
;
}
Map<
String
, Object> decryptedValues =
new HashMap<
>(
)
;
for (PropertySource<
?> source : env.getPropertySources(
)
) {
if (source instanceof EnumerablePropertySource<
?> eps) {
for (String name : eps.getPropertyNames(
)
) {
if (ENCRYPTED_KEYS.contains(name)
) {
Object val = eps.getProperty(name)
;
if (val instanceof String s && s.startsWith("ENC("
) && s.endsWith(")"
)
) {
String cipherText = s.substring(4
, s.length(
) - 1
)
;
try {
String plainText = EncryptionTool.decrypt(key, cipherText, "RSA"
)
;
decryptedValues.put(name, plainText)
;
}
catch (Exception e) {
log.warn("解密配置项 [{}] 失败,保持原密文"
, name, e)
;
}
}
}
}
}
}
if (!decryptedValues.isEmpty(
)
) {
env.getPropertySources(
).addFirst(
new MapPropertySource("decryptedProperties"
, decryptedValues)
)
;
}
log.info("配置文件敏感信息解密完成"
)
;
}
}

关键点说明:

  • 配置扫描与解密:支持 YAML、properties、环境变量等多种配置源。

  • 解密开关灵活控制:通过 config.decrypt.enabled 配置项动态启用或禁用解密逻辑。

  • 优先级注入:通过 addFirst 优先注入解密后的配置,确保后续 Bean 读取时获得明文。

  • 异常安全:解密异常仅警告,保证启动流程不受阻断。

拓展建议

  • 建议将 ENCRYPTED_KEYS 设计为项目可配置项,甚至支持通配符或注解形式,提高灵活性。

  • addFirst 保证解密后的配置覆盖原加密内容,确保业务读取到明文。

3.2 通用解密工具类:EncryptionTool

支持多种主流加密算法,默认实现 RSA 和 AES,使用 Base64 作为密钥和密文的编码方式。

public
class EncryptionTool {
private
static
final String RSA = "RSA"
;
public
static String decrypt(String key, String cipherText, String algorithm)
throws Exception {
if (RSA.equalsIgnoreCase(algorithm)
) {
return decryptByPrivateKey(cipherText, key)
;
}
else {
SecretKey secretKey = decodeKey(key, algorithm)
;
Cipher cipher = Cipher.getInstance(algorithm)
;
cipher.init(Cipher.DECRYPT_MODE
, secretKey)
;
byte[] decrypted = cipher.doFinal(Base64.getDecoder(
).decode(cipherText)
)
;
return
new String(decrypted, StandardCharsets.UTF_8
)
;
}
}
private
static String decryptByPrivateKey(String cipherText, String base64PrivateKey)
throws Exception {
byte[] keyBytes = Base64.getDecoder(
).decode(base64PrivateKey)
;
PrivateKey privateKey = KeyFactory.getInstance(RSA
).generatePrivate(
new PKCS8EncodedKeySpec(keyBytes)
)
;
Cipher cipher = Cipher.getInstance(RSA
)
;
cipher.init(Cipher.DECRYPT_MODE
, privateKey)
;
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder(
).decode(cipherText)
)
;
return
new String(decryptedBytes, StandardCharsets.UTF_8
)
;
}
private
static SecretKey decodeKey(String encodedKey, String algorithm) {
byte[] decodedKey = Base64.getDecoder(
).decode(encodedKey)
;
return
new SecretKeySpec(decodedKey, algorithm)
;
}
}

拓展建议

  • 可实现更多算法,如 DESede(3DES)、ChaCha20,满足不同安全合规需求。

  • 对于性能敏感场景,可考虑解密缓存策略。

四、快速上手指南 ⚡

4.1 依赖引入

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

4.2 注册 EnvironmentPostProcessor

  1. 在Spring Boot 项目的 resources 目录下添加一个文件

    src/main/resources/META-INF/spring.factories

    ⚠️ 注意:路径和文件名都必须完全正确!

  2. 文件内容示例

    org.springframework.boot.env.EnvironmentPostProcessor=\
    com.example.config.DecryptionEnvironmentPostProcessor
    • com.example.config.DecryptionEnvironmentPostProcessor 替换成你自己的类的完整包名。

    • 逗号分隔可以注册多个 EnvironmentPostProcessor

    • 必须没有拼写错误,且类必须能被 Spring Boot classpath 加载。

  3. 示例项目结构(最小可运行)

    your-project/
    ├── src/
    │ └── main/
    │ ├── java/
    │ │ └── com/example/config/
    │ │ └── DecryptionEnvironmentPostProcessor.java
    │ └── resources/
    │ └── META-INF/
    │ └── spring.factories
    ├── pom.xml

4.3 生成密钥

算法说明工具示例
RSA生成一对公私钥,私钥需 PKCS#8 格式 Base64 编码OpenSSL, Keytool
AES生成 128/256 位随机密钥,Base64 编码OpenSSL, Java KeyGenerator

4.4 配置示例

spring:
datasource:
username: db_user
password: ENC(rGA1bK3t...EncryptedText...)
config:
decrypt:
enabled: true

4.5 启动注入密钥

export DB_SECRET_KEY=$(cat /etc/secure/rsa_private_key.pem)
java -jar app.jar --spring.profiles.active=prod

五、安全最佳实践 ?

建议说明
? 专业密钥管理使用 Vault、AWS KMS、Azure Key Vault 等专业平台管理密钥,杜绝硬编码及磁盘持久化。
?️ 最小权限原则严格限制密钥环境变量或文件权限,避免非授权访问。
? 日志审计控制绝不在日志中输出明文或解密结果,防止敏感信息泄露。
? 定期密钥轮换定期更新密钥,缩短密钥生命周期,降低风险。
? 分级加密策略针对不同环境/服务使用独立密钥,降低横向攻击风险。

六、总结 ?

借助本方案,可以实现:

本方案不仅满足高安全标准,还保持了 Spring Boot 配置体系的自然兼容与开发便利性。建议结合项目实际,进一步扩展支持密钥动态更新、配置加密校验等高级特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/928416.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springcloud gateway Error creating bean with name bootstrapImportSelectorConfiguration:

springcloud gateway Error creating bean with name bootstrapImportSelectorConfiguration 修改 gateway 版本 从 2.2.1 ===> 2.1.3<!-- 引入 gateway 依赖 --><dependency><groupId>org.sprin…

做招聘网站需要哪些手续长沙大型网站建设公司

[css] 说说你对前端二倍图的理解&#xff1f;移动端使用二倍图比一倍图有什么好处&#xff1f; 二倍图是指单位面积下设备像素与css像素个数之比为 4 的位图。移动端使用二倍图可以在Retina屏幕下保真展示。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃…

标准网站建设报价单六安在建项目和拟建项目

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的Linux】 文章目录 一&#xff0c;什么是进程地址空间&#xff1f;二&#xff0c;进程地址空间是怎么设计的&#xff1f;三&#xff0c;为什么要有进程地址空间&#xff1f; 一&#xff0c;什…

网站空间控制面板iis7.0建设网站

1、查看进程 ps axuf ---静态查看所有进程#user 用户#PID 每个进程的标识符&#xff0c;父进程为1#VSZ 虚拟内存#RSS 实际内存#pts 窗口 TTY系统启动窗口# %MEM 内存#STAT 该进程的状态&#xff0c;包括&#xff1a;S 可中断睡眠Ss 父进程S< 优先级较高SN…

网站认证必须做么网络广告策划案

移动 表、表分区、LOB字段、索引、分区索引 到另一表空间 alter table 命令移动 table, partition, lob字段alter index 命令移动 索引, 分区索引移动表π 移动表&#xff08;非分区表&#xff09;&#xff1a; alter table <schema.table> move tablespace <new tab…

郑州网站开发网站制作模板网站

Hadoop中自带的hadoop-mapreduce-examples-2.7.6.jar含有一些事例&#xff0c;本文将用pi计算圆周率。若想了解其计算原理&#xff0c;参考&#xff1a;http://thinkinginhadoop.iteye.com/blog/710847。 具体步骤如下&#xff1a; 1. 启动Hadoop 切换到Hadoop安装目录下的sb…

完整教程:PyCharm接入DeepSeek,实现高效AI编程

完整教程:PyCharm接入DeepSeek,实现高效AI编程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", …

Nginx的核心功能及实现

Nginx 核心功能与实现分析 项目概述 Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好。 核…

2025焚烧炉厂家权威推荐,技术实力与市场口碑深度解析

随着环保意识的不断提升和固体废物处理需求的持续增长,焚烧炉作为一种能实现垃圾减量化、无害化处理的关键设备,在市政、工业、医疗等多个领域的应用愈发广泛。然而,当前国内焚烧炉行业呈现出品牌数量多、质量参差不…

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.8 R语言解题 - 指南

实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.8 R语言解题 - 指南2025-10-05 15:25 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important;…

创办一个网站的费用黄山自驾游攻略

随着科技的飞速发展&#xff0c;智慧园区已成为城市现代化建设的重要组成部分。山海鲸可视化智慧园区解决方案&#xff0c;作为业界领先的数字化革新方案&#xff0c;正以其独特的技术优势和丰富的应用场景&#xff0c;引领着智慧园区建设的新潮流。 本文将带大家一起了解一下…

Go 语言中的 panic 详解 - 指南

Go 语言中的 panic 详解 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&quo…

高考加油!UI界面生成器! - 教程

高考加油!UI界面生成器! - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&q…

UnityShader入门精要-系统语义与函数体

系统语义与函数体 系统语义标记,指该类型将返回给流水线GPU做处理。结构体做返回值时,不需要在函数头标记系统语义。结构体外部和内部的标记会产生二义性,所以新版本只能在内部声明原版错误 Shader "Unity Sha…

从价值博弈到价值原语博弈的跃迁:降维解析与升维求解的工程实现——声明Ai研究

从"价值博弈"到"价值原语博弈"的跃迁:降维解析与升维求解的工程实现 一、引言:价值冲突的新理解框架 在当今复杂多变的社会环境中,价值冲突日益成为人类社会面临的核心挑战。从政策制定到伦理决…

免费酒店管理系统+餐饮架构+小程序点餐——仙盟创梦IDE

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

宣讲家网站 家风建设营销导向企业网站策划

思路 选择对应的区域其实是按照表格中的省市区的名字进行匹配 读取文件后对应的字典为&#xff1a; {台湾: {},新疆: {},港澳: {中国澳门: [凼仔岛, nan]},西藏: {昌都地区: [卡若区], 那曲地区: [nan]} } 字典解释例如 市区为空&#xff0c;就是选择省下面的全部市和区 区为空…

企业网站怎做破解付费wordpress主题

功能扩展说明&#xff1a; 图类封装&#xff1a;将图数据结构封装为类&#xff0c;提高代码复用性 最短路径查找&#xff1a;基于BFS实现未加权图的最短路径查找 路径重构&#xff1a;通过parent数组回溯构建完整路径 异常处理&#xff1a;当路径不存在时返回空向量 复杂度分析…

记一次安装fail2ban - Lizo

今天在B站刷到一个视频,大意就是黑客没有变少,只是变得隐蔽了,于是我查了一下我的服务器的访问日志 不是哥么,你当着我的面爆破密码啊 今天查了一下lastb,发现居然有人正在尝试暴力破解我服务器的ssh密码,而且还…

罗湖商城网站建设找哪家公司比较安全外包和劳务派遣哪个更好

一、环境版本 环境版本docker clickhouse22.3.10.22 二、UDF运行速度时快时慢 udf配置文件xxx_function.xml type- 可执行类型。如果type设置为executable则启动单个命令。如果设置为&#xff0c;executable_pool则创建命令池。 pool_size- 命令池的大小。可选参数&#xff…