跟我学shardingjdbc之使用jasypt加密数据库连接密码
生产上我们对数据库连接密码一般都是配置密文,从源头上尽可能地保证安全性。
本文中,我将介绍一款在Spring Boot中使用的自动加解密工具,对数据库连接密码进行加密操作。
该工具名为 jasypt-spring-boot-starter ,能够做到在Spring Boot 加载属性之前,对属性进行进行加解密操作。它使用对称加密方式进行加解密。
项目的Github为 jasypt-spring-boot, 感兴趣的可以去点个star支持下。
话不多说,进入正题。
引入依赖
还是基于我们的demo工程,首先在项目的pom.xml中引入maven依赖。
<!-- 集成数据库密码加密工具jasypt jdk8版本-->
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>1.14</version>
</dependency>
加密明文密码
我们编写一个加密方法对密码明文进行加密操作。代码如下(需要依赖jasypt-spring-boot-starter包)
import org.jasypt.util.text.BasicTextEncryptor;
public class JasyptUtil {
/**
* 加密方法
* @param salt 盐值
* @param targetString 待加密字符串
* @return 密文
*/
public static String encrypt(String salt, String targetString) {
BasicTextEncryptor encryptor = new BasicTextEncryptor();
encryptor.setPassword(salt);
return encryptor.encrypt(targetString);
}
/**
* 解密方法
* @param salt 盐值
* @param targetString 待解密字符串
* @return 明文
*/
public static String decrypt(String salt,String targetString) {
BasicTextEncryptor encryptor = new BasicTextEncryptor();
encryptor.setPassword(salt);
return encryptor.decrypt(targetString);
}
public static void main(String[] args) {
String salt = "salt";
String password = "test";
// 进行加密操作
String encryptString1 = encrypt(salt, password);
// 进行解密操作
String decryptString1 = decrypt(salt, encryptString1);
// 输出明文和密文
System.out.println("encryptString1="+encryptString1);
System.out.println("decryptString1="+decryptString1);
}
}
运行main方法,输出如下:
encryptString1=LIGKpRXjX0FD24N9E/kTsA==
decryptString1=root
解释一下,假设我们的数据库密码明文为:root,盐值为:salt,加密后的密文为:LIGKpRXjX0FD24N9E/kTsA==
在程序中设置密文
上一步中我们得到了连接数据库的密码密文,打开我们应用的配置文件application.properties,修改数据库连接密码为如下格式:
sharding.jdbc.datasource.ds0.password=ENC(LIGKpRXjX0FD24N9E/kTsA==)
通过 ENC(密文) 的方式,在程序中获取到的sharding.jdbc.datasource.ds0.password会自动转换成明文内容(root)。
由于我们加密的时候设置了加密的盐值,因此需要在application.properties中添加盐值,用于解密
#加密盐值
jasypt.encryptor.password=salt
启动方法上配置自动加解密
最后我们还需要在main方法上添加注解开启自动加解密,代码如下
@SpringBootApplication
@MapperScan(basePackages = "com.snowalker.shardingjdbc.snowalker.demo.mapper")
@EnableEncryptableProperties
public class SnowalkerShardingjdbcDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SnowalkerShardingjdbcDemoApplication.class, args);
}
}
注解 @EnableEncryptableProperties 即是开启自动加解密的关键。
启动应用测试
运行main方法,看到日志如下,表示配置生效~
2019-03-14 14:05:44.853 INFO 25252 --- [ main] c.u.j.encryptor.DefaultLazyEncryptor : Encryptor config not found for property jasypt.encryptor.stringOutputType, using default value: base64
2019-03-14 14:05:46.429 INFO 25252 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
2019-03-14 14:05:46.552 INFO 25252 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} inited
2019-03-14 14:05:46.693 INFO 25252 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-3} inited
2019-03-14 14:05:46.818 INFO 25252 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-4} inited
2019-03-14 14:05:47.196 INFO 25252 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-03-14 14:05:48.865 INFO 25252 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8091 (http) with context path ''
2019-03-14 14:05:48.868 INFO 25252 --- [ main] s.d.SnowalkerShardingjdbcDemoApplication : Started SnowalkerShardingjdbcDemoApplication in 6.374 seconds (JVM running for 8.048)
生产环境我们一般使用docker进行应用的部署,因此需要将数据库密码配置为环境变量,只需要修改配置文件application.properties中的密码配置如下:
# 通过ENC(密文)开启密码解密,不使用加密算法时,直接输入原始密码
sharding.jdbc.datasource.ds0.password=${mysql_db_password}
在docker容器启动时候通过-e配置环境变量,我们线上使用了Kubernates管理docker集群,只需要在helm部署文件的valus.yaml中配置环境变量。原理其实是相同的。
docker启动时配置方式如下:
docker run -d -v /log/snowalker/:/log --name sharding-jdbc-demo \
-m 4g \
-p 8081:8081 \
-e db00_url="jdbc:mysql://127.0.0.1:3306/db_00?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8" \
-e db01_url="jdbc:mysql://127.0.0.1:3306/db_01?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8" \
-e db02_url="jdbc:mysql://127.0.0.1:3306/db_02?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8" \
-e db03_url="jdbc:mysql://127.0.0.1:3306/db_03?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8" \
-e db_username=root \
-e db_password="ENC(LIGKpRXjX0FD24N9E/kTsA==)" \
镜像仓库域名:5000/命名空间/sharding-jdbc-demo:1.0.1
核心配置为
-e db_password="ENC(LIGKpRXjX0FD24N9E/kTsA==)" \
注意添加双引号,否则会报错。
如果使用kubernates的helm方式部署,那么只需要在values.yaml中配置密码环境变量如下:
secret:
# 注意key不要使用减号'-'连接单词,如果需要一定使用下划线'_'
# 因为模板会识别key名称,自动并将key对应的值映射到容器中与key名称相同的环境变量上,而环境变量名称不支持减号'-'
# mysql
db00_url: 'jdbc:mysql://127.0.0.1:3306/db_00?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8'
db01_url: 'jdbc:mysql://127.0.0.1:3306/db_01?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8'
db02_url: 'jdbc:mysql://127.0.0.1:3306/db_02?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8'
db03_url: 'jdbc:mysql://127.0.0.1:3306/db_03?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8'
mysql_db_username: 'root'
mysql_db_password: 'ENC(LIGKpRXjX0FD24N9E/kTsA==)'
一定要将整个解密表达式设置到环境变量,如果appliation.properties中密码环境变量设置为如下方式则会报错
错误的配置!
sharding.jdbc.datasource.ds0.password=ENC(${mysql_db_password})
这种配置方式下,‘${mysql_db_password}’不会被识别为环境变量,而是普通的密码字符串,从而报错。
小结
到这里,我们就将数据库连接密码从明文设置为密文,我还在文章后半段讲解了如何通过环境变量设置密文到程序中。这里涉及到分布式开发下的“应用无状态”概念,在后续的文章中我会详细讲解如何开发无状态的应用。
接下来的文章中,我将继续带领读者对Sharding-JDBC进行深入的学习,Keep Moving。
附录:命令行方式使用Jasypt加解密
这里再介绍一种命令行下利用Jasypt加解密的方式。
生成密文
首先通过jasypt jar包生成密文:
D:\repository\org\jasypt\jasypt\1.9.2>
java -cp D:\repository\org\jasypt\jasypt\1.9.2\jasypt-1.9.2.jar
org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="root"
password=salt algorithm=PBEWithMD5AndDES
jasypt需要设置用于加密明文的密钥password,它会对input内容加密。解释下参数:
参数 | 解释 |
---|---|
input | 密码原文 |
password | 加密的盐值 |
algorithm | 加密策略,对称加密 |
命令行下执行该命令,打印如下
----ENVIRONMENT-----------------
Runtime: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 25.181-b13
----ARGUMENTS-------------------
algorithm: PBEWithMD5AndDES
input: root
password: salt
----OUTPUT----------------------
guEfhaqV1d6LTCfhqsk6pQ==
OUTPUT打印的部分就是加密后的密文。
除了通过application.properties方式配置加密的盐值,我们还可以通过启动参数设置该参数,命令如下:
java -jar sharding-jdbc-demo.jar --jasypt.encryptor.password=salt