前言
出于对项目的安全考虑,经常需要对数据库的密码进行加密,本文我们将带大家从源码角度进行分析各个配置的作用,使用druid的自带工具对数据进行加密。
加密代码
public static void main(String[] args) {
String password = "test";
String[] arguments = new String[]{password};
try {
ConfigTools.main(arguments);
} catch (Exception e) {
log.info("生成密文失败,异常信息:{}", e);
}
}
运行后可以得到加密后的密码
-
privateKey:MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlxFiZMO5fD1kOIc/B7R+dUsJ5EsxCXqGAC3SpiAHm/397LgpKi613kPRkzidA7olwT34gkXX7HNQnvYBngRyaQIDAQABAkAxRDUfgYkzUF4n5UuT+rQnEnLGZhM28SNUWZ1SGi4BHAHfp5pbyMEzDD+84hc5r5Euk7HEGkuUt2HNRPq4cpERAiEA4BRm3kfpuVfqSjij3zJ7UdiE54oWeAnG2XiG1hJvdmUCIQCslm8wUxksDgcvNUjQN8Pp9VZCBUzInlppanVZyUB5tQIgUSER3YjL5n8eJKE9M6JjY86wz+P/Hpbrl/E7YGZsVMECIQCPAOtKkGBYJ5t+W1lk5gAYeGertraDuOpTVJm99srMzQIgHX7T20MexhBxokUIQiXuaB8Z9CflpQY7StP/cedt9Wk= publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJcRYmTDuXw9ZDiHPwe0fnVLCeRLMQl6hgAt0qYgB5v9/ey4KSoutd5D0ZM4nQO6JcE9+IJF1+xzUJ72AZ4EcmkCAwEAAQ== password:WCACUuMVJmu01PWDOUphY5Ms7CUhG80WHJi8KqyJpIrQsVEyX5prwedps2YbkJaScUGPApuX6ZiFawfWxaDDyw==
可以看出druid默认的工具类是采用非对称加密的方式进行加密的
其中private是自动生成的随机私密,我们需要关注的值有“publicKey”跟"password",需要保存好着两个值。
配置加密
- 首先我们需要在配置文件中开启加密
从源码中分析
com.alibaba.druid.pool.DruidDataSource#init方法中,遍历了我们所有的filter。
for (Filter filter : filters) {
filter.init(this);
}
为了让揭秘生效,我们需要配置解密的拦截器
spring:
datasource:
druid:
filters: config
- 开启过滤器
这点比较重要,开启后表示druid加载时会走过滤器com.alibaba.druid.filter.config.ConfigFilter,改过滤器将对加密密码进行解密,
public boolean isDecrypt(Properties connectionProperties, Properties configFileProperties) {
// 读取CONFIG_DECRYPT配置,看是否进行加密,只有设置为true才会对数据库进行揭秘
String decrypterId = connectionProperties.getProperty(CONFIG_DECRYPT);
if (decrypterId == null || decrypterId.length() == 0) {
if (configFileProperties != null) {
decrypterId = configFileProperties.getProperty(CONFIG_DECRYPT);
}
}
if (decrypterId == null || decrypterId.length() == 0) {
decrypterId = System.getProperty(SYS_PROP_CONFIG_DECRYPT);
}
return Boolean.valueOf(decrypterId);
}
从上面源码中可以看出,我们还需要配置一个CONFIG_DECRYPT,设置为true。
spring:
datasource:
druid:
connect-properties:
config.decrypt: true
此时会走解密流程,此时会调用com.alibaba.druid.filter.config.ConfigFilter#decrypt方法。
- 公钥跟密码配置
解读decrypt的方法可以看出,我们还需要配置解密的公钥配置
spring:
datasource:
druid:
config.decrypt.key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALwTQSulMoXLHIiwpXY7V1LdLzAusZ3zPOdEHD0fSn6Nc51UAHjRli+pxgIt6M899mXhZ9k2aGzE5weuf9uNTfcCAwEAAQ==
这个公钥就是上面我们main生成的publicKey。配置好公钥后,进行我们的密码解密操作。
此时会读取我们配置的加密后的密码
spring:
datasource:
druid:
password: JjtSWRv9rPnksKAvLZwFuxkpYxbyBxJKFhe5aZGo90BS7HbbQhtEvGCEt75aqDYcyzkkvOfYSxQ5sFKoURWRBQ==
这个password就是我们上面运行main方法生成的加密密码。
补充一点,对于动态数据源的配置:
由于项目中有的用的是多数据源配置:
首先应用baomidou的多数据源maven
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
对于多数据源我们需要关注
com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration类,该类加载了多数据源的配置com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties
从配置中,我们可以看出有专门的druid的一个节点
/**
* Druid全局参数配置
*/
@NestedConfigurationProperty
private DruidConfig druid = new DruidConfig();
查看com.baomidou.dynamic.datasource.spring.boot.autoconfigure.druid.DruidConfig#toProperties中源码:
// 通过判断publicKey值来判断是否加过滤器
if (publicKey != null && publicKey.length() > 0 && !filters.contains(CONFIG_STR)) {
filters += "," + CONFIG_STR;
}
properties.setProperty(FILTERS, filters);
可以看出,我们需要配置一个publicKey,这个key就是我们上面main生成的公钥。
继续阅读下面的代码,会发现利用pulicKey还做了以下事情
Properties connectProperties = connectionProperties == null ? g.getConnectionProperties() : connectionProperties;
// 自动拼接config.decrypt跟config.decrypt.key
if (publicKey != null && publicKey.length() > 0) {
if (connectProperties == null) {
connectProperties = new Properties();
}
connectProperties.setProperty("config.decrypt", Boolean.TRUE.toString());
connectProperties.setProperty("config.decrypt.key", publicKey);
}
this.connectionProperties = connectProperties;
从上面的代码中,可以看出,自动帮我们配置了config.decrypt跟config.decrypt.key,所以我们不需要跟配置druid一样去配置这两个属性,默认开启解密。
最后
此时我们的密码加密就完成了。
总结一下,需要对数据库数据库进行加密,我们需要进行配置四个个地方。如下
spring:
datasource:
druid:
filters: config #配置过滤器
password: ${password} #加密的密钥
connect-properties:
config.decrypt: true #设置为true,开启解密
config.decrypt.key: ${publicKey} #解密的公钥
对于使用的baomidou的多数据源,我们需要配置两个地方,如下:
spring:
datasource:
dynamic:
enabled: true
primary: master
datasource:
master:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://url/dbname?useUnicode=true&characterEncoding=utf-8&
username: test
password: ${passord} #加密的密码
driver-class-name: com.mysql.jdbc.Driver
druid:
filters: config #开启过滤器
publicKey: ${publicKey} #生成的公钥