Hexo

点滴积累 豁达处之

0%

springboot 配置文件加解密

本文演示springboot中yml文件内容采用jasypt进行加解密

1 引入工具包依赖

1
2
3
4
5
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.14</version>
</dependency>

默认情况下jasypt采用的算法是PBEWithMD5AndDES,该算法对同一串明文每次加密的密文都不一样,比较适合做数据加解密。但是该算法必须配置密码,我们在yml文件配置如下参数

1
2
3
jasypt:
encryptor:
password: e!Jd&ljyJ^e4I5oU

如果想要改变其他配置例如密文的前后缀也可以在这里配置。

如果上面引入的包不是starter,那么需要在启动类上添加注解@EnableEncryptableProperties以启动该功能。

然后我们写一个junit测试类,具体内容如下

1
2
3
4
5
6
7
8
9
public class TestBootTest {
@Autowired
StringEncryptor stringEncryptor;//密码解码器自动注入

@Test
public void test() {
System.out.println(stringEncryptor.encrypt("123456"));
}
}

执行后的控制台输出123456加密后的内容:P7xVJnbrn/MCzyVEOejTRw==

我们将spring.datasource.password的值配置为ENC(P7xVJnbrn/MCzyVEOejTRw==),为什么需要这么配置呢,因为默认情况下jasypt-spring-boot解析密码的规则是前缀是ENC(后缀是)。我们改造我们的单元测试工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestBootTest {
@Autowired
StringEncryptor stringEncryptor;//密码解码器自动注入
@Value("${spring.datasource.password}")
private String password;
@Autowired
private UserInfoMapper userInfoMapper;

@Test
public void test() {
// System.out.println(stringEncryptor.encrypt("123456"));
System.out.println("连接数据库密码:" + password);
}
}

启动单元测试,可以看到日志输出了如下内容:

1
连接数据库密码:123456

通过以上方式使用jasypt框架处理配置文件参数加密的功能就基本上OK了,但是存在一定的风险,那就是程序配置文件中,存在解密密文的密码。因为PBEWithMD5AndDES算法到处都可以找到实现。如果拿到了数据库密文和算法的密码,那么很容易解析出连接数据库的密码。一般严谨的做法是不会将密文信息与解密工具放在一起,避免程序被获取后,加密算法和数据库密码密文以及解密密码都同时被泄露。我们公司就是采用C语言写了一个加解密工具,放在服务器上特定的位置。有Java程序中去调用该工具进行解密。那么这种情况下我们怎么自定义解密逻辑呢?

从单元测试中可以看到我们注入了一个加解密的接口StringEncryptor,跟踪改类的实现可以看到系统调用了encrypt方法用于明文加密,调用decrypt对密文进行解密。于是我们实现该接口,假如我们将数据库密码参数spring.datasource.password=123456配置为spring.datasource.password=ENC(654321),那么在该类里面我们要将654321替换为123456,得到我们的真实密码。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DefaultEncryptor implements StringEncryptor {
@Override
public String encrypt(String message) {
if ("123456".equalsIgnoreCase(message)) {
message = "654321";
}
return message;
}

@Override
public String decrypt(String encryptedMessage) {
if ("654321".equalsIgnoreCase(encryptedMessage)) {
log.info("将密文[654321]替换为[123456]");
encryptedMessage = "123456";
}
return encryptedMessage;
}
}

接下来,我们使用java config方式实例化该对象替换默认的StringEncryptor实例,如下

1
2
3
4
@Bean(name = "stringEncryptor")
public StringEncryptor stringEncryptor() {
return new DefaultEncryptor();
}

参考链接