shisongsong 2020-03-11
针对目前越来越严的安全等级要求,我们在做产品研发和项目开发时,越来越需要注意安全问题,各种账号密码的在配置文件中明文存储就是一个很大的安全隐患。
现针对数据库密码加解密方面,利用druid工具类进行数据库加密,实现项目配置文件中数据库密码密文存储,一定程度上保证了数据安全。
步骤一:pom中引入druid依赖
<!-- druid数据源驱动 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
步骤二:添加druid的filter
package com.huatech.cloud.filter;
import java.security.PublicKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class DruidDataSourceFilter extends FilterAdapter {
@Value("${crypto.public-key}")
private String decryptKey;
@Override
public void init(DataSourceProxy dataSourceProxy) {
if (!(dataSourceProxy instanceof DruidDataSource)) {
log.error("ConfigLoader only support DruidDataSource");
return;
}
DruidDataSource dataSource = (DruidDataSource) dataSourceProxy;
// 判断是否需要解密,如果需要就进行解密行动
if (isNotEmpty(decryptKey)) {
decrypt(dataSource);
}
}
public void decrypt(DruidDataSource dataSource) {
try {
String encryptedUsername = null, encryptedPassword = null;
if (encryptedUsername == null || encryptedUsername.length() == 0) {
encryptedUsername = dataSource.getUsername();
}
if (encryptedPassword == null || encryptedPassword.length() == 0) {
encryptedPassword = dataSource.getPassword();
}
PublicKey publicKey = ConfigTools.getPublicKey(decryptKey);
String usernamePlainText = ConfigTools.decrypt(publicKey, encryptedUsername);
String passwordPlainText = ConfigTools.decrypt(publicKey, encryptedPassword);
dataSource.setUsername(usernamePlainText);
dataSource.setPassword(passwordPlainText);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to decrypt.", e);
}
}
public boolean isNotEmpty(String source) {
return source != null && !"".equals(source.trim());
}
}步骤三:通过Druid的ConfigTools工具类生成秘钥对,最后一个参数为待加密内容
java -cp druid-1.1.17.jar com.alibaba.druid.filter.config.ConfigTools abc privateKey:MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAlL2KkAHx1etX6V/A8JrTmLtvd4H/3yectN0RdkEro2z/ItPNdt/gP7W1PTOusSUrD/N4EVbMWNwaUrzBbRYwgwIDAQABAkB9DY693KSyshdLgtH4eHOGabAhzg6OVAOQnHzd65UA5I6sD1ehGT3jjLvNFovenOpzGY0TeYoIonWTlzIb/NJhAiEAyMU9C6l89KIVOiShC/XPEXgj1LtEO4ik/ZlJ6GNbye8CIQC9qDbmctuX8fNeyJMdSluwXjyUNCmVsOE0cnijY37mrQIgTbnudEFdmufVB/l+T78ON1knpggJ1nKETZm2vz0YIAkCIFphz8gC9KN0qoaBD5rl1Mw4HKaENU0g/jIAW32B7PgBAiEAooZbdtng4IrLw47/5SDWiunYrC2BHR59rApQnKkia1A= publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJS9ipAB8dXrV+lfwPCa05i7b3eB/98nnLTdEXZBK6Ns/yLTzXbf4D+1tT0zrrElKw/zeBFWzFjcGlK8wW0WMIMCAwEAAQ== password:N9Noez2waEtPZSjc6UI2v3wZVaORBX5JPPZsL4IxUlFCa49wIhGZF71c3hV6z6Gm3s8MvMk0ief5rWdr5+p63g==
步骤四:application.yml中配置数据源信息和秘钥对公钥
#配置数据源
spring:
datasource:
druid:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/weapp-mall?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useAffectedRows=true
username: N9Noez2waEtPZSjc6UI2v3wZVaORBX5JPPZsL4IxUlFCa49wIhGZF71c3hV6z6Gm3s8MvMk0ief5rWdr5+p63g==password: N9Noez2waEtPZSjc6UI2v3wZVaORBX5JPPZsL4IxUlFCa49wIhGZF71c3hV6z6Gm3s8MvMk0ief5rWdr5+p63g== # rsa算法加解密配置,配置公钥 crypto: public-key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJS9ipAB8dXrV+lfwPCa05i7b3eB/98nnLTdEXZBK6Ns/yLTzXbf4D+1tT0zrrElKw/zeBFWzFjcGlK8wW0WMIMCAwEAAQ==
如果觉得RSA加密算法太过复杂,可以使用jasypt工具类来加解密,具体操作如下。
STEP1:pom.xml中添加依赖
<!-- druid数据源驱动 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<!-- jasypt -->
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>${jasypt.version}</version>
</dependency>STEP2:引入加解密工具类EncryptorTools
package com.huatech.cloud.config;
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentPBEConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@Configuration
public class EncryptorTools implements Ordered {
@Value("${encryptor.password}")
private String password;
@ConditionalOnProperty(name = "encryptor.enable", havingValue = "true", matchIfMissing = true)
@Bean
public StringEncryptor stringEncryptor() {
StandardPBEStringEncryptor standardPBEStringEncryptor = new StandardPBEStringEncryptor();
EnvironmentPBEConfig config = new EnvironmentPBEConfig();
config.setPassword(password);
standardPBEStringEncryptor.setConfig(config);
return standardPBEStringEncryptor;
}
public static String decrypt(StringEncryptor stringEncryptor, final String encodedValue) {
if(stringEncryptor != null) {
try {
return stringEncryptor.decrypt(encodedValue);
}catch(Exception e) {
return encodedValue;
}
}else {
return encodedValue;
}
}
public static String encrypt(StringEncryptor stringEncryptor, final String plainVaue) {
if(stringEncryptor != null) {
try {
return stringEncryptor.encrypt(plainVaue);
}catch(Exception e) {
return plainVaue;
}
}else {
return plainVaue;
}
}
public static String encrypt(String password, String plainText){
StandardPBEStringEncryptor stringEncryptor = new StandardPBEStringEncryptor();
EnvironmentPBEConfig config = new EnvironmentPBEConfig();
config.setPassword(password);
stringEncryptor.setConfig(config);
return stringEncryptor.encrypt(plainText);
}
public static void main(String[] args) {
System.out.println(encrypt("rdc", "root"));
}
@Override
public int getOrder() {
return 0;
}
}STEP3:添加druid的filterJasyptDataSourceFilter
package com.huatech.cloud.filter;
import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.huatech.cloud.config.EncryptorTools;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class JasyptDataSourceFilter extends FilterAdapter {
@Autowired(required = false)
private StringEncryptor stringEncryptor;
@Override
public void init(DataSourceProxy dataSourceProxy) {
if (!(dataSourceProxy instanceof DruidDataSource)) {
log.error("ConfigLoader only support DruidDataSource");
return;
}
DruidDataSource dataSource = (DruidDataSource) dataSourceProxy;
// 判断是否需要解密,如果需要就进行解密行动
dataSource.setUsername(decrypt(dataSource.getUsername()));
dataSource.setPassword(decrypt(dataSource.getPassword()));
}
public String decrypt(String ecryptValue) {
return EncryptorTools.decrypt(stringEncryptor, ecryptValue);
}
}STEP4:application.yml中配置数据源信息和加解密密码信息
# jasypt加解密配置
encryptor:
enable: true
password: rdc
#配置数据源
spring:
datasource:
druid:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/weapp-mall?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useAffectedRows=true
username: 8rYwAh2Qj7E7iqLB7S3QOg==
password: 8rYwAh2Qj7E7iqLB7S3QOg==本文相关代码已上传至gitee