首页 / 帮助文档 / Java Spring Boot配置文件敏感信息使用Jasypt加密

Java Spring Boot配置文件敏感信息使用Jasypt加密

Spring Boot 项目打包成 JAR 后,配置文件 application.properties 或 application.yml 依然是以明文形式存在于 classpath 根目录下。只要解压 JAR 包,任何人都能直接看到数据库地址、账号、密码、第三方 API 密钥等核心敏感信息。这种风险在生产环境中是不可接受的。解决这个问题最直接且与 Spring Boot 生态无缝集成的方案,就是引入 Jasypt 对配置文件中的敏感值进行加密。

Jasypt 解决这个问题的核心逻辑

Jasypt 做的事情并不复杂。它提供了一套加密算法和工具,允许开发者在配置文件中写入密文,然后在 Spring 容器启动加载属性时,自动检测并解密那些被特定格式包裹的密文。应用在运行时读到的是解密后的明文,而配置文件中存储的始终是密文。这样即使配置文件泄露,没有解密密钥也无法还原真实信息。

快速集成 Jasypt 的完整步骤

第一步,在 pom.xml 中添加 Jasypt Spring Boot Starter 依赖。对于 Spring Boot 3.x 项目,需要特别注意版本兼容性,目前推荐使用 jasypt-spring-boot-starter 3.0.5 版本。依赖配置如下:

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

第二步,生成密文。Jasypt 提供了命令行工具和 Maven 插件两种方式。最直接的方法是使用命令行。在项目依赖下载完成后,进入 Maven 仓库中 jasypt 对应版本的 jar 包所在目录,执行加密命令:

java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="你的明文密码" password="你的加密密钥" algorithm=PBEWithMD5AndDES

执行后会输出一串密文。如果不想手动敲命令,更推荐在项目中配置 Maven 插件来生成密文,这样更安全也更方便。在 pom.xml 的 build 标签内添加插件配置:

<plugin>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-maven-plugin</artifactId>
    <version>3.0.5</version>
    <configuration>
        <password>${jasypt.encryptor.password}</password>
    </configuration>
</plugin>

然后通过 Maven 命令执行加密,将需要加密的明文作为参数传入:

mvn jasypt:encrypt-value -Djasypt.encryptor.password="你的加密密钥" -Djasypt.plugin.value="待加密的明文"

第三步,将生成的密文写入配置文件。Jasypt 默认识别 ENC() 包裹的内容。在 application.yml 中的写法如下:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8
    username: ENC(密文内容)
    password: ENC(密文内容)

第四步,配置解密密钥。应用启动时需要知道当初加密所用的密钥才能解密。这个密钥绝对不能写在配置文件中,否则加密就失去了意义。推荐通过启动参数、环境变量或者系统属性来传递。最常用的方式是在启动命令中指定:

java -jar myapp.jar --jasypt.encryptor.password=你的加密密钥

或者设置环境变量 JASYPT_ENCRYPTOR_PASSWORD,Spring Boot 会自动映射。在 IDE 开发环境中,可以在运行配置的 VM options 或环境变量中设置,避免将密钥提交到代码仓库。

自定义加密算法和密钥配置

默认的 PBEWithMD5AndDES 算法在安全性要求较高的场景下已经不够看了。Jasypt 支持更高级的算法,比如 PBEWithSHA256AndAES256。要更换算法,只需在配置文件中添加相关配置。需要注意的是,使用 AES256 算法要求 JDK 安装了 JCE 无限制强度策略文件,这在 JDK 8 某些版本中需要手动处理,而高版本 JDK 默认已启用。配置方式如下:

jasypt:
  encryptor:
    algorithm: PBEWithSHA256AndAES256
    password: ${JASYPT_ENCRYPTOR_PASSWORD}
    key-obtention-iterations: 1000
    pool-size: 1
    provider-name: SunJCE
    salt-generator-classname: org.jasypt.salt.RandomSaltGenerator
    string-output-type: base64

其中 key-obtention-iterations 表示密钥推导的迭代次数,数值越大暴力破解难度越高,但启动时解密性能消耗也越大,通常设为 1000 到 2000 之间即可。pool-size 是解密器池大小,高并发场景下适当调大可提升解密效率。salt-generator-classname 指定盐值生成器,RandomSaltGenerator 会为每次加密生成随机盐,极大增强了安全性。

使用自定义加密器实现更灵活的密钥管理

如果加密密钥本身也需要从外部密钥管理服务获取,或者需要更复杂的密钥派生逻辑,可以实现自己的 StringEncryptor 并注册为 Spring Bean。Jasypt 会优先使用自定义的加密器,而不是默认配置。示例代码如下:

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JasyptConfig {

    @Bean("jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(System.getenv("JASYPT_ENCRYPTOR_PASSWORD"));
        config.setAlgorithm("PBEWithSHA256AndAES256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        return encryptor;
    }
}

这种方式的好处是密钥的获取逻辑完全由开发者掌控,可以从环境变量、系统属性、远程配置中心甚至硬件安全模块中读取,不再局限于启动参数。

测试环境与生产环境的差异化处理

很多团队在开发测试阶段为了方便,会直接把明文写在配置文件中,只在生产环境启用加密。这种做法虽然省事,但容易导致测试环境泄露真实数据。更严谨的做法是从开发环境就统一使用加密配置,只是测试环境可以使用一个简单的、众所周知的密钥,而生产环境使用高强度独立密钥。通过 Spring Profile 可以轻松管理不同环境的加密密钥。在 application-dev.yml 中配置:

jasypt:
  encryptor:
    password: dev-secret-key

而在生产环境中绝不将此配置写入文件,仅通过环境变量或启动参数注入。这样既保证了开发效率,又避免了密钥泄露风险。

加密配置的局限性以及应对策略

Jasypt 加密并非银弹。它只能保护静态配置文件中的敏感信息,一旦应用启动后,内存中的属性值依然是明文。如果攻击者能够 dump JVM 内存或者远程调试,仍然可以获取到解密后的明文。因此 Jasypt 解决的是配置文件泄露风险,而不是运行时内存安全。另外,加密密钥本身的管理是一个棘手问题。密钥需要分发给所有需要启动服务的节点,并且要定期轮换。密钥轮换时,所有用旧密钥加密的密文都需要重新加密,这在微服务数量较多时会是一个运维挑战。建议将密钥托管到公司内部的密钥管理服务中,结合 CI/CD 流水线在部署时动态注入。

与 Spring Cloud Config 配合使用

在使用 Spring Cloud Config 统一管理配置的场景下,Jasypt 同样能发挥作用。Config Server 在提供配置时,如果配置内容包含 ENC() 密文,客户端拉取到本地后由 Jasypt 在客户端侧解密。这意味着 Config Server 的 Git 仓库中存储的也是密文,即使仓库权限管理不当导致泄露,也不会直接暴露敏感信息。需要注意的是,解密密钥需要配置在客户端,也就是每个微服务的启动参数或环境变量中,而不是 Config Server 上。这样 Config Server 只负责传递密文,不参与加解密过程,职责更加清晰。

密文前缀后缀的自定义

默认的 ENC() 标记在某些场景下可能与业务配置值冲突,或者出于安全考虑想隐藏加密痕迹。Jasypt 支持自定义密文的前缀和后缀。在配置文件中设置:

jasypt:
  encryptor:
    property:
      prefix: "SEC("
      suffix: ")"

这样配置文件中的加密值就变成了 SEC(密文) 的格式。自定义前缀后缀可以起到一定的混淆作用,让不熟悉系统的人无法一眼看出哪些值是加密的,但本质上还是依赖密钥的安全性,不能作为主要的安全手段。

常见问题排查思路

集成 Jasypt 后最常见的问题是启动时报解密失败。首先检查加密和解密使用的密钥是否完全一致,包括前后空格。其次确认加密算法是否匹配,默认算法加密的密文用其他算法无法解密。如果使用自定义加密器,检查 Bean 名称是否为 jasyptStringEncryptor,这是 Jasypt 自动配置默认查找的名称。另外,如果配置文件中同时存在明文和密文,Jasypt 只会处理被 ENC() 包裹的值,明文会原样加载,不会报错。如果希望强制所有敏感属性必须加密,可以在代码层面做校验,或者通过单元测试扫描配置文件,确保不包含明文密码等敏感信息。

安全加固的进阶建议

除了使用 Jasypt 加密配置文件,还应当结合其他安全措施形成纵深防御。数据库密码等核心凭证建议定期轮换,并与 Jasypt 密文更新流程打通。应用部署时,配置文件的外部化也是一个好习惯,将敏感配置完全移出 JAR 包,通过文件系统路径或配置中心加载,再配合 Jasypt 加密,双重保障。对于 Kubernetes 环境,可以利用 Secret 资源挂载加密密钥,Pod 启动时通过环境变量注入给 Jasypt,这样密钥不会出现在任何配置文件或代码仓库中。日志输出时要特别注意过滤,避免将解密后的明文密码打印到日志中。可以在日志框架层面配置脱敏规则,对所有包含 password、secret、token 等关键词的字段进行掩码处理。

Jasypt 是目前 Spring Boot 生态中成本最低、集成最平滑的配置加密方案。它不需要改造现有配置加载逻辑,不需要引入额外的中间件,只需几行依赖和配置就能将敏感信息从明文转变为密文。虽然它不能解决所有安全问题,但作为第一道防线,极大提升了攻击者获取配置文件后直接利用的门槛。在监管合规要求日益严格的背景下,对配置文件中的敏感信息进行加密已经不是可选项,而是基本要求。