008.SpringBoot集成Jasypt

682 阅读7分钟

本节目标

  • 了解Jasypt做什么用的
  • 使用Jasypt
  • 几种设置Jasypt盐值的方式

本节项目:在springboot + mybatis plus + 多数据源 + p6spy + Jasypt

Jasypt简介

Jasypt主要是用于在配置文件中,对敏感数据进行加密用的。比如:数据库的连接密码、第三方 Apikey、云服务商的 secretKey等等。

官网地址:github.com/ulisesbocch…

集成Jasypt

参照gitee.com/mayuanfei/S…下的springboot06项目创建springboot07项目。然后在其基础上进行修改。目标是,对现有配置文件中数据库的用户名和密码进行加密。

0. 在其基础上修改

这里说说怎么在springboot06项目基础上快速搭建springboot07项目。

  • 原始项目目录中拷贝springboot06项目

    image-20230606132908095

  • 把springboot06的副本改名称为springboot07

    image-20230606133108326

  • 修改springboot07目录中的springboot06.iml文件名

    image-20230606133649485

  • 在idea中能看到springboot07项目

    image-20230606133304340

    但是此时还没有加入maven项目中管理。

  • pom文件中把springboot06修改为springboot07

    image-20230606140047627

  • idea的maven中添加springboot07项目

    image-20230606134418150

  • 修改项目包名

    image-20230606141049120

    image-20230606141157454

    image-20230606141322926

  • 修改Springboot06Application启动类名称

    和上面相同的方式修改启动类名称为Springboot07Application

    image-20230606141555516

1. SpringBoot三板斧之加入依赖

<!-- Jasypt -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
<!-- 加密包 -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>

说明

如果使用默认的加密提供类,不需要加入下面的加密包的。这里说的默认加密提供其实就是JDK包中rt.jar包中sun.security.provider中的加密算法。但是如果想使用国密、AES256等加密算法,那么这个加密包还是必须的。

2. SpringBoot三板斧之添加配置

# Jasypt配置
jasypt:
  encryptor:
    # 秘钥
    password:  123456

3. 进行测试

@SpringBootTest
public class JasyptTest {
    @Resource
    private StringEncryptor stringEncryptor;
​
    @Test
    //加密后的字符串:JgoBuHD89D4mLiAgtSQ6yg+kAdVc2I35WkTl44hGjfy832UGNtZJyn2fsEGsbehK
    public void testEncrpt() {
        String encrypt = this.stringEncryptor.encrypt("123456");
        Console.log("加密后的字符串:{}", encrypt);
    }
​
    @Test
    //解密后的字符串:123456
    public void testDecrypt() {
        String encrypt = "JgoBuHD89D4mLiAgtSQ6yg+kAdVc2I35WkTl44hGjfy832UGNtZJyn2fsEGsbehK";
        String decrypt = this.stringEncryptor.decrypt(encrypt);
        Console.log("解密后的字符串:{}", decrypt);
    }
}

说明:

  • 通过测试类,可以把要加密的原始字符串进行加密的。
  • 同一个字符串,每次加密出来也是不一样的。

4. 修改配置文件

这里Jasypt模块有个前缀和后缀。ENC(中间是加密后的内容)。

spring:
  datasource:
    dynamic:
      # 性能分析插件(有性能损耗 不建议生产环境使用)
      p6spy: true
      # 严格模式 匹配不到数据源则报错
      strict: true
      # 设置主库.也就是默认操作的数据库
      primary: mysql
      datasource:
        # mysql数据源
        mysql:
          url: jdbc:mysql://192.168.0.1:3306/springboot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: root
          password: ENC(/IjGBG1dthIsPXj9BlHdSXuqQyxLOoYni0z/9vSWbyAvQxhkVq/eWhrbi7D0sGAc)
        # oracel数据源
        oracle18:
          url: jdbc:oracle:thin:@192.168.0.2:1521/test
          username: ENC(fPIEFtxbGPIBLZo7shsEFbFc8Ch+2Y92l92PvwFRfHOypwPv9COv+0QdxpmCDi/C)
          password: ENC(mn8glmWx+FGNX2RzNsccDAHtqkdykyaQKmU/0FG7JX1IH5Aba2q7XT3p0Xx9BJ+T)
          hikari:
            connectionTestQuery: SELECT 1 FROM DUAL
        oracle183:
          url: jdbc:oracle:thin:@192.168.0.3:1521/orcl
          username: ENC(mQq5f1ElDGKNaMpYLjNL3HB1XS9syTJVtUMW3hlSbKFhWZtGf3I2AgyX9qeaDWYQ)
          password: ENC(MYV5caeE7p798/n9rhFOBR49F8xQGfPQ8bAwaSs/I1zG41kd/NB1F4dLv5zvVEhT)
          hikari:
            connectionTestQuery: SELECT 1 FROM DUAL
        # 全局hikariCP配置
        hikari:
          # 最大连接池数量
          maxPoolSize: 20
          # 最小空闲线程数量
          minIdle: 10
          # 配置获取连接等待超时的时间
          connectionTimeout: 30000
          # 校验超时时间
          validationTimeout: 5000
          # 空闲连接存活最大时间,默认10分钟
          idleTimeout: 600000
          # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
          maxLifetime: 1800000
          # 连接测试query(配置检测连接是否有效)
          connectionTestQuery: SELECT 1
          # 多久检查一次连接的活性
          keepaliveTime: 30000

5. 集成完毕

通过简单的一个依赖引入+一个简单的配置,就可以无感使用这个加解密了。配置文件的内容,在使用前就会自动被解密,所以,可以看到我们上课的测试回滚的例子key正常的使用。

Jasypt的配置项

image-20230606161042806

这里是官方给的配置图,从图中可以很明显的看到,除了password为,其他都是可选的。

生成密文的几种方式

1. 在springboot中生成密文

在继承Jasypt中的3.进行测试中已经描述过如何生成密文了

2. 自己写一个主测试类

public class JasyptMainTest {
    // 写一个测试类打印Jasypt所有支持的算法
    public static void getJasyptAllAlgorithmNames() {
        Set algorithms = AlgorithmRegistry.getAllPBEAlgorithms();
        for (Object algorithm : algorithms) {
            System.out.println(algorithm);
        }
        System.out.println("============================");
        Set allDigestAlgorithms = AlgorithmRegistry.getAllDigestAlgorithms();
        for (Object algorithm : allDigestAlgorithms) {
            System.out.println(algorithm);
        }
    }
​
    public static void main(String[] args) {
        getJasyptAllAlgorithmNames();
        PooledPBEStringEncryptor stringEncryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("123456"); // 秘钥
        // 以下是Jasypt3.x版本默认配置
        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");
        stringEncryptor.setConfig(config);
        // 测试加解密
        String original = "laoma";
        String encrypted = stringEncryptor.encrypt(original);
        String decrypted = stringEncryptor.decrypt(encrypted);
        System.out.println("Original: " + original);
        System.out.println("Encrypted: " + encrypted);
        System.out.println("Decrypted: " + decrypted);
        // 另外一种更简便的方式进行加密
        BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
        textEncryptor.setPassword("123456");
        textEncryptor.encrypt(original);
        encrypted = stringEncryptor.encrypt(original);
        decrypted = stringEncryptor.decrypt(encrypted);
        System.out.println("Original: " + original);
        System.out.println("Encrypted: " + encrypted);
        System.out.println("Decrypted: " + decrypted);
    }
}

说明:这个测试方法中还包括查看现在Jasypt中支持的算法。

  • getAllPBEAlgorithms

    PBE(Password-Based Encryption):代表基于密码的加密。可逆的算法

  • getAllDigestAlgorithms:

    Digest:这里翻译为摘要,它是一种将任意长度的输入数据映射到固定长度输出的过程,输出通常称为哈希值、哈希码、哈希和、校验和、消息摘要、数字指纹或简称哈希。不可逆算法

3. 采用Jasypt的maven插件

  • 加入maven插件

    <!-- 在plugins标签中加入 -->
    <!-- Jasypt的maven插件 -->
    <plugin>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-maven-plugin</artifactId>
        <version>3.0.5</version>
    </plugin>
    
  • 在idea的终端中执行命令

    mvn jasypt:encrypt-value -Djasypt.encryptor.password="123456" -Djasypt.plugin.value="laoma"
    

    image-20230607095312467

    image-20230607095417863

  • 解密

    mvn jasypt:decrypt-value -Djasypt.encryptor.password="123456" -Djasypt.plugin.value="3fDX6rbJbe6URmf9bCR0iVNAF05231FGs3HRmoc+Ti6c4qQbHIseFHjFGpLj7Mt9"
    

    image-20230607095802441

秘钥存放的方式

1. 在配置文件中

# Jasypt配置
jasypt:
  encryptor:
    # 秘钥
    password:  123456

这样能获得配置文件的人就能知道密钥,不够安全。但它是一种方便简单的方式。不被推荐的一种方式。

2. 在运行时参数中

在启动Java程序时加参数:-Djasypt.encryptor.password=pkslow,这样就不会把密钥放在代码中去了。

这里拿idea举例:

image-20230607110751894

在实际部署时运行,类似如下命令行语句:

java -jar -Djasypt.encryptor.password=123456 xxx.jar

3. 在系统环境变量中

把密钥放在linux系统的环境变量中去,只有能拿到服务器访问权限的人,才有可能知道密钥在哪。例如:

# 配置profile文件
export JASYPT_PASSWORD = 123456

# 生效 
source /etc/profile

# 运行java程序时
java -jar -Djasypt.encryptor.password=${JASYPT_PASSWORD} xxx.jar

或者在配置文件中加入秘钥设置

jasypt:
  encryptor:
    password: ${JASYPT_PASSWORD}

4. 自定义加密

Jasypt在SpringBoot环境中默认找的加密bean如下:

image-20230607142234623

所以我们自定义加密bean,为了能够覆盖默认的,也叫这个名字,代码如下:

@Configuration
public class JasyptConfig {
    @Bean("jasyptStringEncryptor")
    public StandardPBEStringEncryptor jasyptStringEncryptor() {
        StandardPBEStringEncryptor stringEncryptor = new StandardPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("123456"); // 秘钥
        // 以下是Jasypt3.x版本默认配置
        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");
        stringEncryptor.setConfig(config);
        return stringEncryptor;
    }
}

有了这个配置文件,就不用在yaml中配置Jasypt的相关信息了。密码在类中,除非反编译,否则看不到秘钥。

自定义前后缀

Jasypt默认的加密前缀是以:ENC(开头的;后缀:),如下所示:

password: ENC(/IjGBG1dthIsPXj9BlHdSXuqQyxLOoYni0z/9vSWbyAvQxhkVq/eWhrbi7D0sGAc)

如果修改成自己希望的前后缀,可以修改如下:

#jasypt:
jasypt:
  encryptor:
    property:
      prefix: LM(
      suffix: )

这样就能定义自己的前后缀了,配置后,如下所示:

password: LM(/IjGBG1dthIsPXj9BlHdSXuqQyxLOoYni0z/9vSWbyAvQxhkVq/eWhrbi7D0sGAc)

代码地址

gitee.com/mayuanfei/S…下的springboot07

记忆印记

  • 知道 Jasypt在什么场景下用
  • SpringBoot如何集成Jasypt
  • Jasypt的秘钥如何能更安全
  • Jasypt生成秘钥的方式
  • Jasypt自定义前后缀