加密配置文件新思路:Spring Boot 集成 Jasypt

2,617 阅读6分钟

Jasypt 简介

什么是 Jasypt?

  • Jasypt(Java Simplified Encryption)是一个Java库,它允许开发人员以最小的努力为项目添加基本的加密功能,而无需深入了解密码学的工作原理。
  • 基于标准的高安全性加密技术,适用于单向和双向加密。加密密码,文本,数字,二进制文件
  • 与 Hibernate 的透明集成。
  • 适合集成到基于 Spring 的应用程序中,也可以透明地与 Spring 安全性集成。
  • 用于加密应用程序(即数据源)配置的集成功能。
  • 多处理器/多核系统中高性能加密的特定功能。
  • 开放 API 以与任何 JCE 提供程序一起使用。

官网:www.jasypt.org/

支持的加密功能

Jasypt 基于 Java Cryptography Extension (JCE),支持以下加密功能:

  1. 对称加密:数据加密和解密使用同一个密钥(如 AES、DES)。
  2. 单向加密:如哈希算法(SHA-256),适合存储密码等不可逆信息。
  3. 文件加密:支持二进制文件的加解密。
  4. 配置加密:特别适用于对敏感配置(如数据库密码、API 密钥)的保护。

Jasypt加密场景

  • System Property 系统变量
  • Envirnment Property 环境变量
  • Command Line argument 命令行参数
  • Application.properties 应用配置文件
  • Yaml properties 应用配置文件
  • other custom property sources 其它配置文件

SpringBoot项目中集成jasypt

  • 添加依赖jar
<dependency>
   <groupId>com.github.ulisesbocchio</groupId>
   <artifactId>jasypt-spring-boot-starter</artifactId>
   <version>3.0.5</version>
</dependency>
  • 配置application.yml配置文件
jasypt:
  encryptor:
    # 指定解密算法,需要和加密时使用的算法一致
    algorithm: PBEWithMD5AndDES
    keyObtentionIterations: 1000
    # 指定加密密钥,生产环境请放到启动参数里面
    password: G0CvDz7oJn6
    poolSize: 1
    saltGeneratorClassname: org.jasypt.salt.RandomSaltGenerator
    stringOutputType: base64

jasypt3.0后,默认支持的算法为 PBEWITHHMACSHA512ANDAES_256 ,该算法需要JDK1.9 以上支持或者添加JCE(Java Cryptography Extension 无限强度权限策略文件)支持。

  • 使用工具类加解密
public class JasyptUtils {
    private static final PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    private static final String PASSWORD = System.getProperty("jasypt.encryptor.password", "defaultPassword");

    static {
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setPassword(PASSWORD);
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
    }

    public static String encrypt(String plaintext) {
        try {
            return encryptor.encrypt(plaintext);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    public static String decrypt(String encryptedText) {
        try {
            return encryptor.decrypt(encryptedText);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }
}

  • 配置文件密钥安全性处理
datasource:
    # driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:13306/oauth?characterEncoding=utf-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useSSL=false&useUnicode=true&rewriteBatchedStatements=true
    username: root
    password: ENC(Ifn6fVWW1eA/jVy9fkLhI3pONN/wuCVsm3bfSEzNE10=)

img_4.png

Jasypt 常见加密算法

支持的默认算法一览

Jasypt 提供了多种加密算法,常见的包括以下几种:

算法名称类型说明
PBEWithMD5AndDES对称加密默认算法,使用 MD5 和 DES 结合,适合基础加密需求。
PBEWithHMACSHA512AndAES_256对称加密高级加密算法,支持更高安全性,需 JDK 1.9 或添加 JCE 支持。
PBEWithSHA1AndDESede对称加密使用 SHA1 和 DESede(Triple DES)结合,适合需要更强加密的场景。
PBEWithMD5AndTripleDES对称加密提供更高的安全性,推荐在对性能要求较低的场景使用。
PBEWithSHA256And128BitAES-CBC-BC对称加密支持 AES-128 位加密,适合现代化安全需求。

各算法的特点和适用场景

  1. PBEWithMD5AndDES

    • 特点:性能较好,适合普通加密需求。
    • 适用场景:配置文件加密、敏感信息保护。
  2. PBEWithHMACSHA512AndAES_256

    • 特点:更高强度的加密算法,适合对安全性要求高的场景。
    • 适用场景:企业级应用的关键数据加密,如 API 密钥、数据库配置。
  3. PBEWithSHA1AndDESede

    • 特点:加密强度中等,兼顾性能和安全性。
    • 适用场景:中小型项目的敏感信息加密。
  4. PBEWithMD5AndTripleDES

    • 特点:高安全性,性能稍低。
    • 适用场景:需要持久性存储的重要数据加密。
  5. PBEWithSHA256And128BitAES-CBC-BC

    • 特点:AES 加密提供更现代化的安全性,适合对性能有较高要求的场景。
    • 适用场景:移动端和分布式系统中的配置加密。

Jasypt 使用注意事项

密钥安全管理

  1. 避免硬编码密码
    密钥不应直接写在代码或配置文件中,推荐通过系统环境变量或启动参数传递。

    java -jar app.jar --jasypt.encryptor.password=yourSecretKey
    
  2. 限制密钥权限
    密钥文件或环境变量的访问权限应严格控制,仅允许授权用户和进程访问。

  3. 定期更换密钥
    为提高安全性,应定期更换加密密钥并重新加密存储的数据。

异常处理和日志记录

  1. 加解密异常捕获
    在加解密过程中,可能出现密钥错误、算法不支持等异常,需捕获并记录日志。

    try {
        String encrypted = encryptor.encrypt("plaintext");
    } catch (Exception e) {
        log.error("Encryption failed: ", e);
    }
    
  2. 敏感数据保护
    避免在日志中记录明文数据或加密密钥,以防泄露敏感信息。

性能优化建议

  1. 使用池化加密器
    配置 PooledPBEStringEncryptorpoolSize 参数,根据系统并发需求合理设置线程池大小。

    config.setPoolSize("5");
    
  2. 减少解密操作
    对需要频繁访问的解密数据,推荐缓存解密后的内容,避免重复解密带来的性能开销。

  3. 选择适合的算法
    根据实际需求选择加密算法,简单配置可选择 PBEWithMD5AndDES,复杂场景可选更高级的算法。


真实场景应用

数据库配置加密

将数据库的用户名和密码加密存储,防止配置文件泄露时敏感信息暴露:

datasource:
  url: jdbc:mysql://localhost:3306/mydb
  username: ENC(encryptedUsername)
  password: ENC(encryptedPassword)

敏感信息保护(如 API Key)

在项目中加密存储第三方服务的 API Key:

api:
  key: ENC(encryptedApiKey)

与 Spring Security 集成

通过 Jasypt 加密用户认证信息或加密存储会话令牌,提升应用的安全性。


通过正确使用 Jasypt 提供的加密算法与安全配置,我们可以有效保护敏感信息的安全,同时保证性能与易用性。Jasypt 在 Spring Boot 中的无缝集成,使其成为开发者处理配置加密的首选方案。


测试方式一

# maven依赖:org.jasypt:jasypt
java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI password=xxxyyyzzz algorithm=PBEWithMD5AndDES input="明文"
java -cp jasypt-1.9.2.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI password=xxxyyyzzz algorithm=PBEWithMD5AndDES input=密文
 
 
# 好像是必须带上ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI password=xxxyyyzzz algorithm=PBEWithMD5AndDES ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator input="明文"
java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI password=xxxyyyzzz algorithm=PBEWithMD5AndDES ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator input=密文
 
# maven依赖:com.melloware:jasypt
# com.melloware:jasypt:1.9.4报错:Bad argument: ivGeneratorClassName=org.jasypt.iv.RandomIvGenerator,需要去掉ivGeneratorClassName参数
java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI password=password algorithm=PBEWithMD5AndDES input="XXX"
java -cp jasypt-1.9.4.jar org.jasypt.intf.cli.JasyptPBEStringDecryptionCLI password=password algorithm=PBEWithMD5AndDES input="XXX"

测试方式二

        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("jaspyt_password");
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        //config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        System.out.println(encryptor.encrypt("root"));

测试方式三

import org.jasypt.encryption.StringEncryptor;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
 
 
@SpringBootTest
public class TestAppTest {
    @Resource
    private StringEncryptor stringEncryptor;
 
 
    @Test
    public void testEncrypt() {
        // 加密
        System.out.println(stringEncryptor.encrypt("100"));
 
        // 解密
        System.out.println(stringEncryptor.decrypt("9eO11FBv04dwRC3KUJjpXx0XpfA/nlhWy0ee91bpAlbLJZAlMtlh+pRFnL9HsX8o0do26JwkwnAuqk/RVuwa5FRtAdzwsL2B6ce1vQ43z2hXmbuiUBoDyh0UCbnVHqNX"));
    }
}

秘钥处理

  • 将加密密码以明文形式写在配置文件中并不安全,实际开发中也不推荐这样使用。
  • 打包后部署项目,可以使用如下命令在启动项目时指定秘钥:
#方式1:
java -jar xxx.jar -Djasypt.encryptor.password=加密数据的秘钥

#方式2:
java -jar xxx.jar --jasypt.encryptor.password=加密数据的秘钥

SpringBoot何时解密?

jasypt-spring-boot-starter在服务运行(启动)时会自动对密文进行解密处理