Spring项目中,在默认情况下配置文件的内容都是明文的,但是对于敏感的信息,如中间件的密钥,DB、Redis密码等,直接使用明文存在安全隐患。在对配置文件中敏感信息加密时,常用到的Jasypt工具。
SpringBoot常用配置文件加密工具比较
alibaba.druid
通过alibaba.druid工具加密,但只能用于DB链接相关参数加密,无法实现对其他敏感信息加密
Jasypt
Jasypt工具包加密,可以对任何配置项加密。推荐使用此方法。
在SpringBoot中使用Jasypt
引入maven坐标依赖
需要注意的是jasypt版本和springBoot版本之间的对应关系,如果版本不匹配可能会出现各种其他的问题。
SpringBoot2.1.x 对应使用 jasypt2.10
SpringBoot1.5.x 对应使用 jasypt1.5
博主使用的SpringBoot版本是2.2.13.RELEASE, jasypt版本使用的最新版本3.0.4,实测可行。注意一下 jasypt的2.x和3.x版本在加密算法上是有很大变动的。
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
编写Jasypt工具类
可以通过当前工具类实现对文本的加密和解密操作。
package com.lsz.common.utils;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
/**
* Jasypt3.x 加解密工具类
*
* @author lishuzhen
* @createTime 2022年01月17日 21:05:00
*/
public class JasyptUtil {
private static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";
/**
* Jasypt密钥
*/
private static final String SECRET = "MySecret";
public static void main(String[] args) {
// 需加密的文本
String waitEncryptStr = "123456";
String encryptWithSHA512Str = encryptWithSHA512(waitEncryptStr, SECRET);
System.out.println(String.format("加密前的文本 %s \n加密后的文本 %s", waitEncryptStr, encryptWithSHA512Str));
// 需解密的文本
String waitDecryptStr = "VIiyxE6v8nGD9Y+sxiuhLzsIk/TbmI2p/koN9zXG8lqzzPFzXq2qrDqraXm6kQfR";
String decryptWithSHA512Str = decryptWithSHA512(waitDecryptStr, SECRET);
System.out.println(String.format("解密前的文本 %s \n解密后的文本 %s", waitDecryptStr, decryptWithSHA512Str));
}
/**
* Jasypt加密
*
* @param plainText 待加密的原文
* @param secret 加密秘钥
* @return java.lang.String
* @Description: Jasypt 加密(PBEWITHHMACSHA512ANDAES_256)
*/
public static String encryptWithSHA512(String plainText, String secret) {
// 1. 创建加解密工具实例
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
// 2. 加解密配置
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(secret);
config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
// 为减少配置文件的书写,以下都是 Jasypt 3.x 版本,配置文件默认配置
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);
// 3. 加密
return encryptor.encrypt(plainText);
}
/**
* Jasypt解密
*
* @param encryptedText 待解密密文
* @param secret 解密秘钥
* @return java.lang.String
* @Description: Jasypt 解密(PBEWITHHMACSHA512ANDAES_256)
*/
public static String decryptWithSHA512(String encryptedText, String secret) {
// 1. 创建加解密工具实例
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
// 2. 加解密配置
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(secret);
config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
// 为减少配置文件的书写,以下都是 Jasypt 3.x 版本,配置文件默认配置
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);
// 3. 解密
return encryptor.decrypt(encryptedText);
}
}
运行main方法
结果如下: 可以看到目前已经拿到了加密后的文本。注意相同的文本多次执行加密得到的密文是不一样的,解密的结果是一样的。
密文写入配置文件
将工具类得到的密文,加上 ENC() 特殊标记,写入的配置文件。
jasypt加密密钥处理
主要有两种方式存储密钥。
直接写入到SpringBoot的配置文件中
但是这种方式并不能安全,如果密钥暴露,加密也没有任何意义。不建议使用此方法
jasypt:
encryptor:
password: MySecret
在启动命令中加入密钥
通过此方式可以保证 在代码中是找不到密钥的。线上生产环境由运维人员控制,只要保证无法攻击进入服务器,密钥就是安全的。
linux jar包启动脚本
java -jar -Djasypt.encryptor.password=MySecret hello.jar
idea开发环境
方法1-加入启动参数
通过此方法加入的参数和linux jar启动脚本原理一致
方法2-重写Spring配置文件
通过次方法和直接将密码写入配置文件方法原理一致,只不过一个是个代码层面实现,一个是在IDE中通过工具写入。
启动项目
启动日志中可以看到,目前用到的都是Jasypt的默认配置
Jasypt原理
JasyptSpringBootAutoConfiguration
在com\github\ulisesbocchio\jasypt-spring-boot-starter\3.0.4\jasypt-spring-boot-starter-3.0.4.jar!\META-INF\spring.factories文件中,指定boot的配置类。在获取application.yml的配置项时,通过JasyptSpringBootAutoConfiguration处理。
将PropertySource委托给Jasypt处理
重写了gerProperty方法,当需要获取配置的时候,全部都Jasypt处理。
解密
上文中提到的关键字 ENC() ,解密方法中就是通过前缀和后缀判断配置项的参数是否需要的解密的。 在项目配置时,主要避开这个关键字。