前言:
近期所做的项目进入测试阶段,在源码扫描时被检测出一些安全风险,其中就有配置文件中连接数据库的密码不能以明文展示这一问题。思考一下如果以明文展示确实会有很大的安全隐患,万一得罪一些深藏不露的黑客大佬,那数据库就面临被攻击的风险。接下来介绍的也是我试验了好几个版本最终得出的一个较为简单的方法,当然每个人的项目版本,以及依赖等等都不相同,不能保证我认为最简单的在其他项目上也适用,所以如果此方法不行不要着急,多翻几篇文章总有一个适合你。
话不多说,上正文:
1.引入jasypt相关依赖
我用的是3.0.3版本,默认使用的是 PBEWITHHMACSHA512ANDAES_256 高级的算法加密(还有一种低版本的加密方式是MD5,这个不做过多讲解,自行查找),SHA512和DAES_256,前者为不可解加密后者可解加密,两者具体实现原理可自行百度。
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2.创建加密解密的工具包(一键cv)
package com.wangxiaobai.utils;
import com.wangxiaobai.common.Constants;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
/**
* 配置文件中密码加解密工具类
*/
public class JasypUtil {
private static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";
/**
* @Description: Jasyp 加密(PBEWITHHMACSHA512ANDAES_256)
* @param plainText 待加密的原文
* @param factor 加密秘钥
* @return java.lang.String
*/
public static String encryptWithSHA512(String plainText, String factor) {
// 1. 创建加解密工具实例
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
// 2. 加解密配置
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(factor);
config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
// 为减少配置文件的书写,以下都是 Jasyp 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);
}
/**
* @Description: Jaspy解密(PBEWITHHMACSHA512ANDAES_256)
* @param encryptedText 待解密密文
* @param factor 解密秘钥
* @return java.lang.String
*/
public static String decryptWithSHA512(String encryptedText, String factor) {
// 1. 创建加解密工具实例
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
// 2. 加解密配置
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(factor);
config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);
// 为减少配置文件的书写,以下都是 Jasyp 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);
}
public static void main(String[] args) {
String factor = Constants.JASYPT_PASSWORD_CODE; // 这里我用的常量类,自己可以直接写string类型字符串
String plainText = "123456";
String encryptWithSHA512Str = encryptWithSHA512(plainText, factor);
String decryptWithSHA512Str = decryptWithSHA512(encryptWithSHA512Str, factor);
System.out.println("采用AES256加密前原文密文:" + encryptWithSHA512Str);
System.out.println("采用AES256解密后密文原文:" + decryptWithSHA512Str);
}
}
3.添加密钥
在配置文件中添加密钥以及加密形式,密钥要与工具类中的factor保持一致,如果密钥不同则不能解密。加密格式也要与工具类中的字段一致。
jasypt.encryptor.password= wangxiaobai
jasypt.encryptor.algorithm=PBEWITHHMACSHA512ANDAES_256
4.修改配置文件
将自己的数据库连接密码用上述工具类运行生成加密串,将生成的加密串用ENC(加密串) 这种形式将明文密码替换掉。用ENC包裹是因为是根据ENC前缀进行解码,当项目运行时会自动识别,当发现有ENC包裹的加密串,则会自动解码,如果没有用他包裹则项目运行时就不能自动解密。
database.url=jdbc:postgresql://127.0.0.1:5433/aaa?useUnicode=true&characterEncoding=utf8&useSSL=true
database.username=pgsql
database.password=ENC(3qNVZYY0dnpLy+5e5aH9XQg9o9ddarmVg7Cc98rtyDJjRI7Gj7Wd0epxcqVB+V4a)
database1.url=jdbc:postgresql://127.0.0.1:5433/testmm?useUnicode=true&characterEncoding=utf8&useSSL=true
database1.username=pgsql
database1.password=ENC(6a1VH8MQKj9IFZBYjlXXkUtUYIuxF1ebyk2zWSBXIl7WkQuXH5OWj6y70Qd4VEqi)
我的配置文件中连接了两个数据库,都加密即可。
如果自爱配置文件中有其他密码也可以按照此种方式进行加密,多个密码与一个密码没有区别。
以上代码在运行时没有发现别的错误,如果大家在运行过程中有错误可以考虑一下是不是版本不匹配。
当我把源码提交机器检测的时候竟然又发现密码不安全定位错误位置到第3步的密钥password上,原来机器将这个也当做密码,那怎么办?解决呗
这也有两种方式:
第一既然密码都可以加密,那把密钥也加密不就行了,所以把密钥也用ENC()这种格式进行加密。注意:密钥加密之后直接运行的话会报错,数据库链接密码不能解密。是因为我们的密钥已经更新了虽然解密后跟之前一样但是必须写法不一样了,所以要用最新的密钥把之前的数据库密码重新生成加密串。对,没错就是要把加密过后的加密串写在工具类中的factor字段上。
第二既然他是扫描配置文件中所有password字段,那就不把密钥的password写在配置文件中呗。
将配置文件中的密钥删除,在启动类上加入密钥当项目启动时也是先扫描到密钥进行解密
同样我这里边用的是我项目中自己写的常量类中的字段代替string类型的密钥(我有现成的为何不用), 如果不想写的话可以直接写string类型的密钥,当然前提不管怎么写这个密钥一定要和工具类中的保持一致。
好了,到底了~~~~~~~~~~