SpringBoot用jasypt加密敏感配置

配置文件里的数据库密码、API密钥等敏感信息不能明文存放。jasypt 插件支持自动加解密 ENC() 包裹的密文,也能自定义前缀和加密算法。关键是密钥别硬编码,要从环境变量或启动参数传入。

配置文件里躺着一堆敏感信息,数据库密码、Redis 密码、第三方接口的密钥,全是明文。

代码一提交,这些东西就跟着进了仓库,谁拉代码谁都能看见。

我在一个 SpringBoot 3.x 的项目上就被这个问题卡住过,试了好几种方案,最后落在 jasypt 这个插件上,用下来挺顺手。

这篇就把我踩过的点捋一遍:怎么接入、自动模式和自定义模式各自怎么玩,以及最容易翻车的密钥存放问题。

为什么要加密配置

先说清楚我们到底在防什么。

配置明文最大的风险不是"被黑客攻破",而是"无意泄露"。

代码仓库被 fork、日志里打印了配置、运维截图发群里,这些场景下明文密码就直接裸奔了。

所以目标很简单:让配置文件里看到的是一串密文,程序运行时再还原成真实值。

jasypt 干的就是这件事。

它在 Spring 读取配置的环节插了一脚,发现是密文就解密,发现是明文就原样放行。

对业务代码几乎无感,@Value 和 @ConfigurationProperties 该怎么写还怎么写。

引入依赖

用的是社区维护的 starter,自动配置能力都在这个包里。

<!-- jasypt 的 SpringBoot starter,自动接管配置解密 -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <!-- 版本按项目的 SpringBoot 版本挑,3.x 项目用 3.0.x 这一支 -->
    <version>3.0.5</version>
</dependency>
​

加完依赖,@SpringBootApplication 启动时就会自动把解密能力装配进去。

整个属性源都会被它接管,系统属性、环境变量、application.yml 全在覆盖范围内。

自动配置模式

如果你没有自定义加密算法的需求,这个模式几乎零代码。

配一个加密密码

jasypt 需要一把"口令"来加解密,先在配置里给它。

# 这把口令是加解密的根,千万别直接写死在这里(下面会讲怎么安全存放)
jasypt.encryptor.password=MEBUGS
​

生成密文

拿着这把口令,用 jasypt 自带的命令行工具把明文加密。

去 Maven 本地仓库找到 jasypt 的 jar,执行:

# input 是要加密的明文,password 是上面那把口令,algorithm 指定算法
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI \
  input=mebugs_db_pwd \
  password=MEBUGS \
  algorithm=PBEWithMD5AndDES
​

跑完会吐出一串密文(每次结果都不一样,因为带了随机盐)。

这里插一句:PBEWithMD5AndDES 是老算法,强度一般。

新项目建议换成 PBEWITHHMACSHA512ANDAES_256 这种更现代的,jasypt 3.x 默认就是它,省得自己纠结。

密文填回配置

把生成的密文用 ENC() 包起来写进配置文件。

# ENC() 是 jasypt 的识别标记,括号里放密文
spring.datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm58eq...)
​

启动项目,jasypt 看到 ENC() 就自动解密,spring.datasource.password 拿到的是真实密码。

是不是没动一行业务代码?

自定义加解密模式

自动模式够用了,但有两种情况我会切到自定义:

  1. 想换掉 ENC() 这个标记,用自己约定的前缀。
  2. 想用自己的加密算法,比如项目里已经有一套 RSA 工具类。

做法是实现 EncryptablePropertyResolver 接口,自己接管"怎么判断是密文"和"怎么解密"。

/**
 * 自定义配置解密:用 EN*# 开头标记密文,内部走项目自己的 RSA 工具
 *
 * @author mebugs.com
 */
@Configuration
public class EncryptPropertyConfig {

    // RSA 私钥。注意:这里只是演示位置,真实私钥绝不能硬编码(见最后一节)
    private static final String PRIVATE_KEY = loadPrivateKeyFromEnv();

    /**
     * 覆盖掉 jasypt 默认的解析器,Bean 名字必须是这个
     */
    @Bean("encryptablePropertyResolver")
    public EncryptablePropertyResolver encryptablePropertyResolver() {
        return new RsaPropertyResolver();
    }

    static class RsaPropertyResolver implements EncryptablePropertyResolver {
        @Override
        public String resolvePropertyValue(String value) {
            // 不是我们约定的前缀,原样返回,当明文处理
            if (value == null || !value.startsWith("EN*#")) {
                return value;
            }
            // 砍掉前缀 EN*#,剩下的才是真正的密文
            String cipher = value.substring(4);
            try {
                return RSAUtils.decrypt(cipher, PRIVATE_KEY);
            } catch (Exception e) {
                // 解密失败直接抛,让启动失败,别偷偷用一个错值跑起来
                throw new IllegalStateException("配置解密失败: " + value, e);
            }
        }
    }

    private static String loadPrivateKeyFromEnv() {
        // 从环境变量读私钥,而不是写死在代码里
        String key = System.getenv("APP_RSA_PRIVATE_KEY");
        if (key == null || key.isEmpty()) {
            throw new IllegalStateException("缺少环境变量 APP_RSA_PRIVATE_KEY");
        }
        return key;
    }
}
​

配置文件这边就改成自己的前缀:

# 用 EN*# 开头,jasypt 的 ENC() 标记在这个模式下就不认了
spring.datasource.password=EN*#MIGfMA0GCSqGSIb3DQ...
​

有个小坑我提一句:早期网上不少文章会把私钥直接写成 public static String PRIVATE_KEY = "..." 贴在类里。

这等于把保险箱和钥匙放一起,加密就白做了。

PS:官方文档对这点没特别强调,但真上线千万别这么干。

密钥到底该放哪

这才是整篇最该较真的地方。

加密的强度,最终取决于那把口令(或私钥)藏得够不够好。

如果口令还是明文写在 application.yml 里,那加密就是自欺欺人,攻击者拿到配置文件连带口令一起拿走。

几种我用过的存放方式,按推荐度排:

  • 启动参数传入:java -jar app.jar --jasypt.encryptor.password=真实口令,口令不落盘。
  • 环境变量:export JASYPT_ENCRYPTOR_PASSWORD=真实口令,配合容器编排的 secret 管理。
  • 外部密钥服务:接 Vault、KMS 这类专门的密钥管理,程序启动时去拉,安全但接入成本高。

绝对不要做的:把口令提交进代码仓库,或者打进镜像的配置文件里。

一句话原则:密文可以进仓库,密钥不能进仓库。

小结

jasypt 解决的事情很聚焦,就是让配置文件里的敏感项以密文形态存在。

自动模式用 ENC() 包密文,零代码接入,日常够用。

自定义模式实现 EncryptablePropertyResolver,能换前缀、换算法,适合已有加密体系的项目。

但工具只是手段,真正的安全边界在密钥管理上:密文入库,密钥走启动参数或环境变量,别让钥匙跟保险箱躺在一起。

把这条守住,这套方案才算真的立住了。

更多推荐

章节目录