在项目中一般会将数据库,Redis等一些连接配置信息放在Properties(属性配置)文件中,Spring配置文件中通过context:property-placeholder 引入,需要属性的地方使用${属性key}的方式。在SpringBoot项目中,这些配置信息则在yml文件中。出于安全的考虑,一般会将这些信息进行加密
其实加密的思路就是:自定义加密规则,加密明文得到密文,使用密文替换明文,继承placeholder,在自定义的placeholder中进行解密,Spring配置文件使用自定义的placeholder引入配置文件。这些操作完全可以自己去实现而不用借助第三方,但是使用jasypt更加简化这些步骤
jasypt
我这里采用PBEWithMD5AndDES加密方法,每次运行得到的密文都是不一样的,但是可以通过这些密文解密得到唯一的明文,这种加密方法也属于可逆加密的一种,也只有可逆加密方法才适合对配置信息进行加密,毕竟涉及到加密和解密双向操作
jasypt与Spring整合
引入依赖
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt-spring31</artifactId>
<version>1.9.3</version>
</dependency>
加密明文得到密文
直接通过jasypt的api进行加密
public static void main(String[] args) {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
// 设置密钥
config.setPassword("password");
// 设置加密方法
config.setAlgorithm("PBEWithMD5AndDES");
encryptor.setConfig(config);
// 加密
String encryptStr = encryptor.encrypt("123456");
System.out.println(encryptStr);
// 解密
// System.out.println(encryptor.decrypt(encryptStr));
}
加密和解密必须使用同一个密钥
通过一个main方法直接得到需要的密文,接下来在属性文件中进行替换
使用密文替换明文
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///maven
jdbc.user=root
jdbc.password=ENC(/a2d+QFXZXOl79sTxozVEw==)
这里只针对password进行加密,实际上所有的属性都可以加密,但是必须使用ENC(密文)的格式,这是jasypt规定的
配置jasypt
配置jasypt有两种方式:通过XML,通过配置类。
XML方式
<!--配置加密方式及密钥-->
<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<!--加密方式-->
<property name="algorithm" value="PBEWithMD5AndDES"/>
<!--密钥-->
<property name="password" value="MYPASSWORD"/>
</bean>
<!--配置加密器,将用于解密-->
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration"/>
</bean>
<!-- 使用EncryptablePropertyPlaceholderConfigurer引入属性文件 不再使用context:property-placeholder-->
<bean id="placeholderConfig" class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor"/>
<property name="locations">
<list>
<!--根据实际情况替换成项目属性文件位置-->
<value>classpath:/properties/jdbc.properties</value>
<value>file:D://properties//jdbc.properties</value>
</list>
</property>
</bean>
配置类方式
package com.config;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
import org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
@Configuration
public class EncryPropertiesConfig {
/**
* 配置加密方式及密钥
* @return
*/
@Bean
public EnvironmentStringPBEConfig getEnvironmentStringPBEConfig() {
EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
// 设置加密方式
config.setAlgorithm("PBEWithMD5AndDES");
// 设置密钥
config.setPassword("MYPASSWORD");
return config;
}
/**
* 配置加密器,将用于解密
* @return
*/
@Bean
public StandardPBEStringEncryptor getStandardPBEStringEncryptor() {
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setConfig(getEnvironmentStringPBEConfig());
return encryptor;
}
/**
* 引入属性文件
* @return
*/
@Bean
public EncryptablePropertyPlaceholderConfigurer getEncryptablePropertyPlaceholderConfigurer() {
EncryptablePropertyPlaceholderConfigurer placeholderConfigurer = new EncryptablePropertyPlaceholderConfigurer(getStandardPBEStringEncryptor());
placeholderConfigurer.setLocation(new ClassPathResource("/properties/jdbc.properties"));
placeholderConfigurer.setLocation(new FileSystemResource("D://properties//jdbc.properties"));
return placeholderConfigurer;
}
}
将这个配置所在的包配置在context:component-scan扫描范围下,这样就可以了
<context:component-scan base-package="com.lynu;com.config"></context:component-scan>
jasypt与SpringBoot整合
引入依赖
<dependency>
<groupId>com.github.ulisesbocchio</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
加密明文得到密文
同Spring整合的方法一样,写一个main方法调用jasypt的api,这里不在复述
使用密文替换明文
# 数据源配置
datasource:
url: jdbc:mysql:///maven
driver-class-name: com.mysql.jdbc.Driver
username: root
password: ENC(/a2d+QFXZXOl79sTxozVEw==)
这里同样需要使用ENC(密文)的格式
配置jasypt
jasypt:
encryptor:
algorithm: PBEWithMD5AndDES
password: MYPASSWORD
其他加密方案
Spring中使用jasypt,实际上就是替换placeholder进行的,如果项目中的某些配置,没有使用 placeholder + ${} 的方法,又该如何配置呢?
- 自定义加解密方法
- 加密明文得到密文,使用密文替换,只不过不用ENC()的格式了,因为是我们自定义的方案
- 将XML中的配置改为Java类的配置方法,在配置类中解密
我实现过Quartz
和Logback
的,二者都有操作数据库的连接信息(Quartz将定时配置在数据库,Logback往数据库中insert日志)
Quartz
参考的是 【Quartz】解密properties配置文件中的账号密码
Logback
我通过继承DataSourceConnectionSource
,重写方法getConnection()
方法,在这个方法中对密码进行解密
更多jasypt
加密方法与使用技巧,可以参考jasypt官网 以及 jasypt-spring-boot的github地址