您的位置 首页 java

jasypt-spring-boot加密组件的使用与坑爹的死锁

一、前言

最新公司为了提高代码安全性,要求数据库,kakfa, redis 的连接不能直接明文配置。找了很多方案最终发现这个 jasypt-spring-boot组件,但也被这个组件坑炸了,为什么呢?因为出现 死锁 的问题。线上直接P0级别事故,现在我们来复盘一下这个死锁问题。首先分享一下如何集成这个组件。

二、如何集成

1、引入jasypt-spring-boot加密组件的starter(特别说明出现死锁的版本:3.0.3)

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

2、jasypt常用参数说明

2.1、algorithm与 iv -generator-classname对应关系

algorithm

iv-generator-classname

版本

PBEWithMD5AndDES

org.jasypt.iv.NoIvGenerator

3.0.0已下版本

PBEWITHHMACSHA512ANDAES_256

org.jasypt.iv.RandomIvGenerator

3.0.0以上版本

如果对应错误启动的时候会报以下错误

Failed to bind properties under ‘xxx.xxx.xxx’ to java.lang.String

2.2、配置说明

 #自定义加密密钥,对配置文件里的重要项进行加密
jasypt:
  encryptor:
    password: xiao              #加密算法密钥
    property:
      prefix: ENC(              #算法识别前缀,加密后的账号密码需要用这个包起来
      suffix: )                 #算法识别后缀
    algorithm: PBEWITHHMACSHA512ANDAES_256 #默认加密算法
    iv-generator-classname: org.jasypt.iv.RandomIvGenerator  

algorithm加密算法要与IvGeneratorClassName对应的值配套

2、正常的明文配置文件yml (安全级别为0)

 server:
  port: 10000
spring:
  application:
    name: xixien
  datasource:
    url:  jdbc :mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username:  root 
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource  

3、通过工具类生成加密后的账号,密码

 package com.xixien.api.base.utils;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;

public class JasyptUtils {
    public  static   void  main(String[] args) {
        String username = encrypt("root");
        String password = encrypt("123456");
        System.out.println("加密后的账号:"+username);
        System.out.println("加密后的密码:"+password);
        System.out.println("加密前的账号:"+decrypt(username));
        System.out.println("加密前的密码:"+decrypt(password));
    }

    /**
     * 加密
     * @param plaintext 明文密码
     *
     */    public static String encrypt(String plaintext) {
        //加密工具
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        //加密配置
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        // 算法类型
        //config.setAlgorithm("PBEWithMD5AndDES");
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        //生成秘钥的公钥
        config.setPassword("xiao");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        //应用配置
        encryptor.setConfig(config);
        //加密
        return encryptor.encrypt(plaintext);
    }

    /**
     * 解密
     *
     * @param ciphertext 待解密秘钥
     *
     */    public static String decrypt(String ciphertext) {
        //加密工具
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        //加密配置
        EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
        //config.setAlgorithm("PBEWithMD5AndDES");
        
        //生成秘钥的公钥
        config.setPassword("xiao");
        //加密算法要与IvGeneratorClassName对应的值配套
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        //应用配置
        encryptor.setConfig(config);
        //解密
        return encryptor.decrypt(ciphertext);
    }

}
  

main行数运行结果

替换名为配置

原来的明文密码值,改为 ENC(xxx) ,其中xxx是密文。

 server:
  port: 10000
spring:
  application:
    name: xixien
  datasource:
    url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: ENC(9dGDBltW5Q9ealpUkaoEQyup4CSDr7Gz+CKpat3Uq99Wwaz7In4PyKKPSJOs+stK)
    password: ENC(q1KCCS7dSI1eznFC9i7ml3cuGRPjhXYswqkgJWAffMJlkS1I4E35GiQqsv8gHYpx)
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
#自定义加密密钥,对配置文件里的重要项进行加密
jasypt:
  encryptor:
    password: xiao              #加密算法密钥(例子我们放这里)
    property:
      prefix: ENC(              #算法识别前缀,加密后的账号密码需要用这个包起来
      suffix: )                 #算法识别后缀
    algorithm: PBEWITHHMACSHA512ANDAES_256 #默认加密算法
    iv-generator-classname: org.jasypt.iv.RandomIvGenerator  

自定义加密前后缀:

默认前缀prefix=ENC( 后缀 suffix= ) 这个可以自己随心所欲的替换比如LOL()

 jasypt:
  encryptor:
    property:
      prefix: LOL(              #算法识别前缀,加密后的账号密码需要用这个包起来
      suffix: )    

看完这些你是否思考了

三、如何更安全

1、使用自定义加密器

下面是一个自定义加密器bean,可以看到除了一些在yml文件中配置的属性还多了配置(加上了注释的代码),源码类 JasyptEncryptorConfigurationProperties中有些默认配置

 @Configuration
public class XiaoXiongEncryptorCfg {

    //默认bean为jasyptStringEncryptor
    @Bean( name = "xiaoXiongEncryptorBean" )
    public StringEncryptor xiaoXiongEncryptorBean() {
 
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
 
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword("xiao");
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        //源码默认值
        config.setKeyObtentionIterations("1000");
        //源码默认值
        config.setPoolSize("1");
        //源码默认值
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");
        //源码默认值
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
 
        return encryptor;
    }
}  

2、密钥不放在配置文件中

  • 方式一 :直接作为程序启动时的 命令行参数 来带入

java -jar project.jar –jasypt.encryptor.password=xiao

  • 方式二 :直接作为程序启动时的 应用环境变量 来带入

java -Djasypt.encryptor.password=xiao -jar project.jar

  • 方式三 :甚至可以作为 系统环境变量 的方式来带入

比方说,我们提前设置好系统环境变量JASYPT_ENCRYPTOR_PASSWORD = xiao,则直接在Spring Boot的项目配置文件中做如下配置即可:

jasypt.encryptor.password= ${ JASYPT_ENCRYPTOR_PASSWORD }

死锁

我线上的某个业务触发了这个死锁。程序表现为假死,最后通过分析堆栈日志找到这个死锁。也在github上第277的issues发现了端倪。真是脑裂呀

1、原因

jasypt-spring-boot加密组件的使用与坑爹的死锁

jasypt-spring-boot加密组件的使用与坑爹的死锁

2、修改后的代码

文章来源:智云一二三科技

文章标题:jasypt-spring-boot加密组件的使用与坑爹的死锁

文章地址:https://www.zhihuclub.com/185663.shtml

关于作者: 智云科技

热门文章

网站地图