Spring Boot 应用中实现配置文件敏感信息加密解密方案
Spring Boot 应用中实现配置文件敏感信息加密解密方案
- 背景与挑战 🚩
- 一、设计目标 🎯
- 二、整体启动流程 🔄
- 三、方案实现详解 ⚙️
- 3.1 配置解密入口:`EnvironmentPostProcessor`
- 3.2 通用解密工具类:`EncryptionTool`
- 四、快速上手指南 ⚡
- 4.1 依赖引入
- 4.2 注册 `EnvironmentPostProcessor`
- 4.3 生成密钥
- 4.4 配置示例
- 4.5 启动注入密钥
- 五、安全最佳实践 🔐
- 六、总结 🎉
背景与挑战 🚩
在现代企业级应用中,application.yml
或 application.properties
常用于配置数据库(DataSource)、Redis、RabbitMQ 等中间件的连接信息。
spring:datasource:username: myuserpassword: my-secret-password
但问题来了:
将明文密码直接写入配置文件中存在诸多风险,主要包括:
❌ 风险类型 | 详细描述 |
---|---|
代码仓库泄露风险 | 配置文件可能被误提交到 Git 等版本管理系统,导致敏感信息外泄。 |
构建与发布风险 | 打包过程或日志文件可能暴露敏感数据,带来安全隐患。 |
调试与共享风险 | 第三方人员或调试时可能接触到明文,增加信息暴露概率。 |
因此,敏感信息必须避免以明文形式存储。
一、设计目标 🎯
目标 | 说明 |
---|---|
🔒 零明文配置 | 配置文件中敏感字段均以 ENC(...) 形式存储,无明文密码。 |
⚙️ 自动解密 | 应用启动时自动解密,业务代码无感知,无需改动。 |
🔄 多算法支持 | 兼容 RSA、AES 等主流加密算法,满足不同安全需求。 |
🎛️ 开关灵活 | 支持配置及环境变量动态启停解密功能,满足多环境多场景。 |
🤝 无侵入业务代码 | 保持 Spring Boot 原生配置机制,业务层透明使用解密后的配置。 |
二、整体启动流程 🔄
-
密钥注入
通过环境变量(如
DB_SECRET_KEY
)注入 RSA 私钥或对称密钥。 -
EnvironmentPostProcessor 扫描
Spring Boot 启动时自动加载实现了
EnvironmentPostProcessor
的解密组件。 -
配置源扫描
遍历所有
PropertySource
,查找形如ENC(...)
的密文字段。 -
调用解密工具
根据配置的算法(RSA/AES)还原明文。
-
注入环境变量
将解密后的结果以
MapPropertySource
形式优先加载,覆盖原加密值。 -
后续加载
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");@Overridepublic 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
-
在Spring Boot 项目的
resources
目录下添加一个文件:src/main/resources/META-INF/spring.factories
⚠️ 注意:路径和文件名都必须完全正确!
-
文件内容示例
org.springframework.boot.env.EnvironmentPostProcessor=\ com.example.config.DecryptionEnvironmentPostProcessor
-
com.example.config.DecryptionEnvironmentPostProcessor
替换成你自己的类的完整包名。 -
逗号分隔可以注册多个
EnvironmentPostProcessor
。 -
必须没有拼写错误,且类必须能被 Spring Boot classpath 加载。
-
-
示例项目结构(最小可运行)
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_userpassword: 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 配置体系的自然兼容与开发便利性。建议结合项目实际,进一步扩展支持密钥动态更新、配置加密校验等高级特性。
相关文章:

Spring Boot 应用中实现配置文件敏感信息加密解密方案
Spring Boot 应用中实现配置文件敏感信息加密解密方案 背景与挑战 🚩一、设计目标 🎯二、整体启动流程 🔄三、方案实现详解 ⚙️3.1 配置解密入口:EnvironmentPostProcessor3.2 通用解密工具类:EncryptionTool 四、快速…...

【TTS】基于GRPO的流匹配文本到语音改进:F5R-TTS
论文地址:https://arxiv.org/abs/2504.02407v3 摘要 我们提出了F5R-TTS,这是一种新颖的文本到语音(TTS)系统,它将群体相对策略优化(GRPO)集成到基于流匹配的架构中。 通过将流匹配TTS的确定性输出重新表述为概率高斯分布,我们的方…...

动态规划-152.乘积最大子数组-力扣(LeetCode)
一、题目解析 根据示例nums数组中存在负数,下面分析时需注意 二、算法原理 1、状态表示 此时f[i]表示:以i位置为结尾的所有子数组中的最大乘积,但是由于nums中存在负数,所以还需要g[i]表示:以i位置为结尾的所有子数组…...

1-1 初探Dart编程语言
Dart 是 Google 最初开发的一种开源编程语言,适用于客户端与服务端开发。它配套提供 Dart SDK,其中包含 Dart 编译器、Dart 虚拟机(Dart VM)以及一个名为 dart2js 的工具,可将 Dart 脚本转换为 JavaScript,…...

搭建最新版开源监控平台SigNoz踩的坑
转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权并注明出处。感谢您喜爱本文,请文明转载,谢谢。 一、前言 SigNoz 是一款开源应用程序性能监控工具,在往期相关文章(文末有链接)中…...
Ubuntu 服务器配置与 Cloudflare Tunnel 部署指南 免费内网穿透家用服务器
Ubuntu 服务器配置与 Cloudflare Tunnel 部署指南 本文档总结了服务器配置相关内容,包括 Ubuntu 服务器配置、硬盘扩容、静态 IP 设置以及 Cloudflare Tunnel 的部署步骤。 目录 硬盘分区与扩容设置静态 IPCloudflare Tunnel 部署SSH 通过 Cloudflare Tunnel常见…...

无人机多人协同控制技术解析
一、运行方式 无人机多人点对点控制通常采用以下两种模式: 1. 主从控制模式 指定一个主控用户拥有最高优先级,负责飞行路径规划、紧急操作等关键指令;其他用户作为观察者,仅能查看实时画面或提交辅助指令,需经主…...

【东枫科技】KrakenSDR 测向快速入门指南
本快速入门指南旨在帮助您使用运行在 Raspberry Pi 4/5 或 Orange Pi 5B (OPI5B)(带 WiFi 型号)上的 KrakenSDR 尽快连接到测向应用程序。不过,请务必阅读本手册的其余部分,以了解无线电测向的工作原理。 你需要什么 本指南假设…...
使用LangChain与多模态模型实现图像中的文字和表格提取(PDF可转图片)
引言 在实际工程应用中,经常需要处理含有工程检验标准、施工图纸等复杂内容的PDF文档。这些文档往往包含大量水印、背景图层或无关信息,直接使用OCR识别容易引入噪声,影响后续的信息处理与分析。 为了解决这一问题,我尝试通过网页版Qwen进行测试,发现其对图像中的文字和…...

【Redis】hash
Hash 哈希 几乎所有的主流编程语言都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射等。在 Redis 中,哈希类型指值本身又是一个键值对结构,形如 key “key”, value {{field1, value1}, …{field…...

基于Vite的前端自动化部署方案
👨 作者简介:大家好,我是Taro,全栈领域创作者 ✒️ 个人主页:唐璜Taro 🚀 支持我:点赞👍📝 评论 ⭐️收藏 文章目录 前言一、主流解决方案二、了解SCP概念三、自动化部署…...

antDesignVue中a-upload上传组件的使用
工作中需要使用上传组件,记录一下a-upload部分属性用法 1.showUploadList属性使用 使用:showUploadList"{ showRemoveIcon: true ,showDownloadIcon: true }"属性可控制右侧下载,删除图标 2.如何实现回显功能 使用:defaultFileList"fil…...

龙舟竞渡与芯片制造的共通逻辑:华芯邦的文化破局之道
端午节承载着中华民族数千年的精神密码,龙舟最初是古人沟通天地、祈求风调雨顺的仪式载体。战国时期,屈原投江的悲壮故事为端午注入了家国情怀,龙舟竞渡从此兼具纪念英雄与祈福避疫的双重意义。这种文化内核,与深圳市华芯邦“以科…...

机房网络设备操作安全管理制度
该制度围绕机房网络设备操作安全,规定账号实行系统管理员、操作管理员、一般用户三级分级管理,遵循最小授权和权限分割原则,账号需实名制、禁止共享及转借,密码设置需至少 8 位、3 种字符组合且每 3 个月修改一次;高危指令执行需上级审批、双人核查,远程登录需限制权限、…...
CentOS中安装Docker Compose
在CentOS中安装Docker Compose的步骤如下: 步骤 1:确保Docker已安装 Docker Compose依赖Docker环境,请先安装Docker: # 添加Docker官方仓库 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://downlo…...
Linux Kernel动态调试:运行时调试的利器
前言 之前我们在 Linux Kernel调试:强大的printk(二) Linux Kernel调试:强大的printk(三) 文章中介绍过pr_debug和dev_dbg,如下是dev_dbg的定义: #if defined(CONFIG_DYNAMIC_DEBUG) || \(defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_M…...

Milvus分区-分片-段结构详解与最佳实践
导读:在构建大规模向量数据库应用时,数据组织架构的设计往往决定了系统的性能上限。Milvus作为主流向量数据库,其独特的三层架构设计——分区、分片、段,为海量向量数据的高效存储和检索提供了坚实基础。 本文通过图书馆管理系统的…...

5月课程精彩回顾 | 2025高通边缘智能创新应用大赛系列公开课
当边缘计算与人工智能的碰撞掀起技术革命浪潮,如何抢占创新先机?2025高通边缘智能创新应用大赛以行业顶尖资源赋能开发者,在初赛阶段重磅打造系列公开课。 5月13日至29日,大赛主办方高通技术公司携手承办方阿加犀,以及…...

设计模式25——中介者模式
写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。 中介者模式(Mediat…...

阿里云配置安全组策略开放端口
目录 1. 测试端口是否开放 1.1 测试程序 1.2 测试工具 2. 阿里云安全组开放端口 3. 测试开放之后是否能访问 1. 测试端口是否开放 1.1 测试程序 Linux: This repository is specifically designed to store Linux code - Gitee.comhttps://gitee.com/Axurea/linux/tree/…...

uniapp 搭配uviwe u-picker 实现地区联栋
原始数据: ["id": 2,"createTime": null,"updateTime": null,"citycode": null,"adcode": "410000","cityName": "河南省","level": "province","cent…...

win10电脑时间同步失败的解决方法
win10电脑时间同步失败 问题如下: 解决方法如下: 搜索里搜索:控制面板,然后选择时钟和区域 
Cantor 表的探究与实现 在数学中,有理数的可枚举性是一个令人惊叹的结论。今天,就让我们一起深入探讨这个经典问题,并分享一段精心编写的代码,揭开这一数学奥秘的神秘面纱。 问题背景 在 19 世纪末,伟大的数学家康托…...

代码随想录打卡|Day53 图论(Floyd 算法精讲 、A * 算法精讲 (A star算法)、最短路算法总结篇、图论总结 )
图论part11 Floyd 算法精讲 代码随想录链接 题目链接 代码 三维DP数组 import java.util.Scanner;public class Main {// 定义最大距离值,避免使用Integer.MAX_VALUE防止加法溢出public static final int INF 100000000; // 10^8足够大且不会溢出public static…...

yum安装nginx后无法通过服务方式启动
背景 在linux系统下,通过yum方式安装nginx后 通过nginx命令 nginx 可以启动nginx 但是作为测试或者生产服务器,我们需要配置开机自启动,这时候需要用服务方式启动 yum安装后的nginx 已经默认生成了服务启动方式的 nginx.service文件 按…...

数据基座觉醒!大数据+AI如何重构企业智能决策金字塔(下)
1. 数据架构的量子跃迁 1.1 从线性堆叠到立体网络 传统六层架构正在经历基因重组。某智能家居企业将数据流转路径重构为三维拓扑网络后,新品研发周期从18个月压缩至9个月。这个改造的核心在于打破数据层间的物理隔离,让原始数据流能直接触达决策中枢。…...

在线博客系统【测试报告】
🕒 一. 项目背景 由于纸质笔记容易丢失,携带不变,为了方便自己学习的过程中记录笔记,特开发了这个博客系统。这个系统后端采用 SpringBoot MyBatis SpringMVC ;前端使用Html CSS JS;数据库使用的是Mysq…...

Void:免费且隐私友好的 AI 编码利器,挑战 Cursor 地位?
开发者圈儿里最近有点小激动,大家都在议论一个叫Void的开源AI代码编辑器。这家伙在GitHub上人气飙涨,短时间内就斩获了超过22.1k的星标,简直成了科技圈的新宠。它被誉为“黑马”,不仅因为它继承了大家都很熟悉的Visual Studio Cod…...

Elasticsearch的写入流程介绍
Elasticsearch 的写入流程是一个涉及 分布式协调、分片路由、数据同步和副本更新 的复杂过程,其设计目标是确保数据一致性、可靠性和高性能。以下是写入流程的详细解析: 一、写入流程总览 二、详细步骤解析 1. 客户端请求路由 请求入口:客户端(如 Java 客户端、REST API)…...

【PCB工艺】PCB设计中的基本概念
此文结合实例讲解PCB的设计流程和一些基本概念。 🧱 PCB 是什么? PCB(Printed Circuit Board)(即印制线路板) 是电子元器件的载体,是没有焊接任何器件的“裸板”。 PCB只是板子,没有焊接元件,而PCBA可以理解为焊接好元件的完成板子。 简单点说,PCB 只包含:铜线、电源…...