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

news2025/6/2 7:53:39

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

  • 背景与挑战 🚩
  • 一、设计目标 🎯
  • 二、整体启动流程 🔄
  • 三、方案实现详解 ⚙️
    • 3.1 配置解密入口:`EnvironmentPostProcessor`
    • 3.2 通用解密工具类:`EncryptionTool`
  • 四、快速上手指南 ⚡
    • 4.1 依赖引入
    • 4.2 注册 `EnvironmentPostProcessor`
    • 4.3 生成密钥
    • 4.4 配置示例
    • 4.5 启动注入密钥
  • 五、安全最佳实践 🔐
  • 六、总结 🎉


背景与挑战 🚩

在现代企业级应用中,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.coloradmin.cn/o/2393412.html

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

相关文章

【TTS】基于GRPO的流匹配文本到语音改进:F5R-TTS

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

动态规划-152.乘积最大子数组-力扣(LeetCode)

一、题目解析 根据示例nums数组中存在负数&#xff0c;下面分析时需注意 二、算法原理 1、状态表示 此时f[i]表示&#xff1a;以i位置为结尾的所有子数组中的最大乘积&#xff0c;但是由于nums中存在负数&#xff0c;所以还需要g[i]表示&#xff1a;以i位置为结尾的所有子数组…

1-1 初探Dart编程语言

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

搭建最新版开源监控平台SigNoz踩的坑

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权并注明出处。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 一、前言 SigNoz 是一款开源应用程序性能监控工具&#xff0c;在往期相关文章&#xff08;文末有链接&#xff09;中…

无人机多人协同控制技术解析

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

【东枫科技】KrakenSDR 测向快速入门指南

本快速入门指南旨在帮助您使用运行在 Raspberry Pi 4/5 或 Orange Pi 5B (OPI5B)&#xff08;带 WiFi 型号&#xff09;上的 KrakenSDR 尽快连接到测向应用程序。不过&#xff0c;请务必阅读本手册的其余部分&#xff0c;以了解无线电测向的工作原理。 你需要什么 本指南假设…

【Redis】hash

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

基于Vite的前端自动化部署方案

&#x1f468; 作者简介&#xff1a;大家好&#xff0c;我是Taro&#xff0c;全栈领域创作者 ✒️ 个人主页&#xff1a;唐璜Taro &#x1f680; 支持我&#xff1a;点赞&#x1f44d;&#x1f4dd; 评论 ⭐️收藏 文章目录 前言一、主流解决方案二、了解SCP概念三、自动化部署…

antDesignVue中a-upload上传组件的使用

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

龙舟竞渡与芯片制造的共通逻辑:华芯邦的文化破局之道

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

机房网络设备操作安全管理制度

该制度围绕机房网络设备操作安全,规定账号实行系统管理员、操作管理员、一般用户三级分级管理,遵循最小授权和权限分割原则,账号需实名制、禁止共享及转借,密码设置需至少 8 位、3 种字符组合且每 3 个月修改一次;高危指令执行需上级审批、双人核查,远程登录需限制权限、…

Milvus分区-分片-段结构详解与最佳实践

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

5月课程精彩回顾 | 2025高通边缘智能创新应用大赛系列公开课

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

设计模式25——中介者模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 中介者模式&#xff08;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 实现地区联栋

原始数据&#xff1a; ["id": 2,"createTime": null,"updateTime": null,"citycode": null,"adcode": "410000","cityName": "河南省","level": "province","cent…

win10电脑时间同步失败的解决方法

win10电脑时间同步失败 问题如下&#xff1a; 解决方法如下: 搜索里搜索:控制面板&#xff0c;然后选择时钟和区域 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d734b28553514f6699d559d4218e5e99.png 此处输入:ntp.aliyun.com 然后时间就同步完成了~ 可以…

代码随想录打卡|Day53 图论(Floyd 算法精讲 、A * 算法精讲 (A star算法)、最短路算法总结篇、图论总结 )

图论part11 Floyd 算法精讲 代码随想录链接 题目链接 代码 三维DP数组 import java.util.Scanner;public class Main {// 定义最大距离值&#xff0c;避免使用Integer.MAX_VALUE防止加法溢出public static final int INF 100000000; // 10^8足够大且不会溢出public static…

yum安装nginx后无法通过服务方式启动

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

数据基座觉醒!大数据+AI如何重构企业智能决策金字塔(下)

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