SpringBoot:配置Jasypt加密yml配置文件属性

前言

  数据安全问题频出,公司开始对数据安全进行严加管控,其中代码开发配置文件中的敏感信息不能明文存放必须密文处理,所以特此记录下Jasypt加解密方式。

imageimage

框架环境

  博主自己框架的版本信息

<!--   SpringBoot版本   -->
<spring-boot.version>3.2.8</spring-boot.version>
<!--   SpringCloud版本   -->
<spring-cloud.version>2023.0.3</spring-cloud.version>
<!--   SpringCloud-Alibaba版本   -->
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
<!--   Spring Ai 人工智能框架版本   -->
<spring-ai.version>1.0.0</spring-ai.version>
<!--   bootstrap.yml加载版本   -->
<bootstrap.version>3.1.0</bootstrap.version>

Jasypt依赖

<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version> <!-- Spring Boot 2.x:推荐 Jasypt 2.1.x 或 3.0.x。  Spring Boot 3.x:推荐 Jasypt 3.0.5 或更高版本。 -->
</dependency>

重点因为博主框架使用SaToken做鉴权,Gateway内就需要引用SaToken做鉴权过滤,但SaToken需要连接redis,而redis密码使用Jasypt作加密需要解密,最后Gateway(WebFlux)与Jasypt(Servlet)响应式环境冲突,导致启动失败。有相同问题的可以看这篇文章https://www.cnblogs.com/nhdlb/p/19542319

配置类初始化Jasypt

  网上使用yml配置文件加载Jasypt并通过java -jar命令传递密码的方式较多,博主这里使用的是配置类加载Jasypt,后续使用jar加密后就看不到了,如果使用命令行传递(java -Djasypt.encryptor.password=xxxxxx -jar xxx.jar )并用docker部署的话还是会将密码暴露出来。这里只是多一层考虑,大家根据自己实际情况来评估怎么使用。

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;

/**
 * Jasypt配置文件加密密文
 * @author zy
 */
@Configuration
public class JasyptConfig {

    private static final String password = "JGk3d8r";

    // 冲突:因Gateway内引用SaToken做鉴权,但SaToken需要连接redis,而redis密码使用Jasypt作加密需要解密,最后Gateway(WebFlux)与Jasypt(Servlet)响应式环境冲突,导致启动失败
    // 自定义加密器, 封装在代码内,不暴露出去
    @Bean("jasyptStringEncryptor")
    public StringEncryptor jasyptStringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        // 配置文件加密的密码,写死;后续使用jar加密就可以了
        //config.setPassword(password); 
        // 也可以使用命令行传递密码, java -Djasypt.encryptor.password=mypassword -jar xxxxx.jar
        config.setPassword(System.getProperty("jasypt.encryptor.password"));
        // 指定加密方式 可以查看JasyptUtil工具类有哪些加密方式
        config.setAlgorithm(JasyptUtil.PBE_WITHHMACSHA_512_ANDAES_256);
        // 设置密钥派生过程中的迭代次数。迭代次数越高,暴力破解成本越高
        // 1000 是较保守的值,现代推荐至少 10,000~100,000(如 Spring Security 默认 PBKDF2 用 185,000)
        config.setKeyObtentionIterations("100000");
        // 设置加密器池的大小,"1" 表示只使用一个实例(适用于低并发或单线程场景)
        config.setPoolSize("1");
        // 指定 Java 加密服务提供者(Security Provider)。"SunJCE" 是 Oracle JDK 自带的默认加密提供者,支持大多数标准算法
        config.setProviderName("SunJCE");
        // 指定盐值(Salt)生成器类
        // Salt 是随机数据,用于防止彩虹表攻击。每次加密都会生成不同的 salt,即使明文相同,密文也不同。
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        // 设置加密后输出的字符串编码格式
        config.setStringOutputType("base64");
        // 不需要 IV 的算法,org.jasypt.iv.NoIvGenerator
        // 使用 CBC、GCM 等需要 IV 的模式 时(例如 AES/CBC),就必须提供 IV 生成器 org.jasypt.iv.RandomIvGenerator
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        encryptor.setConfig(config);
        return encryptor;
    }

}

 Jasypt工具类

   用于生成密文与解密密文的工具类

import com.higentec.common.utils.spring.SpringUtils;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentPBEConfig;

public class JasyptUtil {

    /**
     * PBE 算法
     */
    public static final String PBE_ALGORITHMS_MD5_DES = "PBEWITHMD5ANDDES";
    public static final String PBE_ALGORITHMS_MD5_TRIPLEDES = "PBEWITHMD5ANDTRIPLEDES";
    public static final String PBE_ALGORITHMS_SHA1_DESEDE = "PBEWITHSHA1ANDDESEDE";
    public static final String PBE_ALGORITHMS_SHA1_RC2_40 = "PBEWITHSHA1ANDRC2_40";
    public static final String PBE_WITHHMACSHA_512_ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";
    public static final String PBE_WITHHMACSHA_256_ANDAES_256 = "PBEWITHHMACSHA256ANDAES_256";
    public static final String PBE_WithMD5AndTripleDES = "PBEWithMD5AndTripleDES";
    public static final String PBE_WithHmacSHA_1_AndAES_128 = "PBEWithHmacSHA1AndAES_128";
    public static final String PBE_WithHmacSHA_256_AndAES_128 = "PBEWithHmacSHA256AndAES_128";

    private JasyptUtil() {
    }

    /**
     * Jasypt 加密
     *
     * @param encryptedStr 加密字符串
     * @param password     盐值
     * @return
     */
    public static String encrypt(String encryptedStr, String password) {
        return encrypt(encryptedStr, PBE_WITHHMACSHA_512_ANDAES_256, password);
    }

    /**
     * Jasypt 加密
     *
     * @param encryptedStr 加密字符串
     * @param algorithm    加密算法
     *                     PBE ALGORITHMS: [PBEWITHMD5ANDDES, PBEWITHMD5ANDTRIPLEDES, PBEWITHSHA1ANDDESEDE, PBEWITHSHA1ANDRC2_40]
     * @param password     盐值
     * @return
     */
    public static String encrypt(String encryptedStr, String algorithm, String password) {
        // StandardPBEStringEncryptor、StandardPBEBigDecimalEncryptor、StandardPBEBigIntegerEncryptor、StandardPBEByteEncryptor
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        EnvironmentPBEConfig config = new EnvironmentPBEConfig();
        // 指定加密方式 可以查看JasyptUtil工具类有哪些加密方式
        config.setAlgorithm(algorithm);
        // 配置文件加密的密码
        config.setPassword(password);
        // 设置密钥派生过程中的迭代次数。迭代次数越高,暴力破解成本越高
        // 1000 是较保守的值,现代推荐至少 10,000~100,000(如 Spring Security 默认 PBKDF2 用 185,000)
        config.setKeyObtentionIterations("100000");
        // 设置加密器池的大小,"1" 表示只使用一个实例(适用于低并发或单线程场景)
        config.setPoolSize("1");
        // 指定 Java 加密服务提供者(Security Provider)。"SunJCE" 是 Oracle JDK 自带的默认加密提供者,支持大多数标准算法
        config.setProviderName("SunJCE");
        // 指定盐值(Salt)生成器类
        // Salt 是随机数据,用于防止彩虹表攻击。每次加密都会生成不同的 salt,即使明文相同,密文也不同。
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        // 不需要 IV 的算法,org.jasypt.iv.NoIvGenerator
        // 使用 CBC、GCM 等需要 IV 的模式 时(例如 AES/CBC),就必须提供 IV 生成器 org.jasypt.iv.RandomIvGenerator
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        encryptor.setConfig(config);
        // 加密
        return encryptor.encrypt(encryptedStr);
    }

    /**
     * Jasypt 解密
     *
     * @param decryptStr 解密字符串
     * @param password   盐值
     * @return
     */
    public static String decrypt(String decryptStr, String password) {
        return decrypt(decryptStr, PBE_WITHHMACSHA_512_ANDAES_256, password);
    }

    /**
     * Jasypt 解密
     *
     * @param decryptStr 解密字符串
     * @param algorithm  指定解密算法:解密算法要与加密算法一一对应
     *                   PBE ALGORITHMS: [PBEWITHMD5ANDDES, PBEWITHMD5ANDTRIPLEDES, PBEWITHSHA1ANDDESEDE, PBEWITHSHA1ANDRC2_40]
     * @param password   盐值
     * @return
     */
    public static String decrypt(String decryptStr, String algorithm, String password) {
        // StandardPBEStringEncryptor、StandardPBEBigDecimalEncryptor、StandardPBEBigIntegerEncryptor、StandardPBEByteEncryptor
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        EnvironmentPBEConfig config = new EnvironmentPBEConfig();
        // 指定加密方式 可以查看JasyptUtil工具类有哪些加密方式
        config.setAlgorithm(algorithm);
        // 配置文件加密的密码
        config.setPassword(password);
        // 设置密钥派生过程中的迭代次数。迭代次数越高,暴力破解成本越高
        // 1000 是较保守的值,现代推荐至少 10,000~100,000(如 Spring Security 默认 PBKDF2 用 185,000)
        config.setKeyObtentionIterations("100000");
        // 设置加密器池的大小,"1" 表示只使用一个实例(适用于低并发或单线程场景)
        config.setPoolSize("1");
        // 指定 Java 加密服务提供者(Security Provider)。"SunJCE" 是 Oracle JDK 自带的默认加密提供者,支持大多数标准算法
        config.setProviderName("SunJCE");
        // 指定盐值(Salt)生成器类
        // Salt 是随机数据,用于防止彩虹表攻击。每次加密都会生成不同的 salt,即使明文相同,密文也不同。
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        // 不需要 IV 的算法,org.jasypt.iv.NoIvGenerator
        // 使用 CBC、GCM 等需要 IV 的模式 时(例如 AES/CBC),就必须提供 IV 生成器 org.jasypt.iv.RandomIvGenerator
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        encryptor.setConfig(config);
        // 解密
        return encryptor.decrypt(decryptStr);
    }

    /**
     * 使用自定义加密器进行加密
     * @param str 需要进行加密的字符串
     */
    public static String encrypt_customize(String str){
        StringEncryptor encryptor = SpringUtils.getBean("jasyptStringEncryptor", StringEncryptor.class);
        return encryptor.encrypt(str);
    }

    /**
     * 使用自定义加密器进行解密
     * @param str 需要进行解密的密文
     */
    public static String decrypt_customize(String str){
        StringEncryptor encryptor = SpringUtils.getBean("jasyptStringEncryptor", StringEncryptor.class);
        return encryptor.decrypt(str);
    }

//    public static void main(String[] args) {
//        String encryptedStr = "12345678ab";
//        String algorithm = PBE_WITHHMACSHA_512_ANDAES_256;
//        String password = "y0BwPTcN";
//        String str = JasyptUtil.encrypt(encryptedStr, algorithm, password);
//        System.out.println("加密后的字符串:" + str);
//        System.out.println("解密后的字符串:" + JasyptUtil.decrypt(str, algorithm, password));
//    }

}

 yml配置文件

# Spring
spring:
  application:
    # 应用名称
    name: base-system
  profiles:
    #环境配置
    active: @profiles.active@
  # 冲突:因Gateway内引用SaToken做鉴权,但SaToken需要连接redis,而redis密码使用Jasypt作加密需要解密,最后Gateway(WebFlux)与Jasypt(Servlet)响应式环境冲突,导致启动失败
  # 手动优先加载 Jasypt 配置文件解密Bean实体
  cloud:
    bootstrap:
      # 多个可以使用,号分隔
      sources: com.higentec.common.config.JasyptConfig

# Jasypt配置文件解密
jasypt:
  encryptor:
    # 引用手动优先加载的解密Bean
    bean: jasyptStringEncryptor

image

重点: 使用加密后的密文需要用 ENC(密文) 包裹起来,如此Jasypt才能识别哪些需要解密。

image

posted @ 2026-01-28 10:23  怒吼的萝卜  阅读(1)  评论(0)    收藏  举报