0、脫敏規則
1、環境構建
1.1、創建一個 Spring Boot 項目,引入依賴如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.zwqh</groupId>
<artifactId>sharding-sphere-4.1.1</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>cn.zwqh</groupId>
<artifactId>sharding-sphere-demo-8</artifactId>
<version>${parent.version}</version>
<packaging>jar</packaging>
<name>sharding-sphere-demo-8</name>
<description>Demo project for Spring Boot</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.zwqh.shardingspheredemo8.ShardingSphereDemo8Application</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
1.2、測試數據庫 ds1
CREATE TABLE `t_user` (
`user_id` int NOT NULL COMMENT '用戶id',
`user_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用戶名稱',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼明文',
`password_encrypt` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密碼密文',
`password_assisted` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '輔助查詢列',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
1.3、實體類
@Data
public class UserEntity {
private Integer userId;
private String userName;
private String password;
private String passwordEncrypt;
private String passwordAssisted;
}
1.4、Mapper
@Mapper
public interface UserMapper {
@Insert("insert into t_user(user_id,user_name,password) values(#{userId},#{userName},#{password})")
void insertUser(UserEntity userEntity);
@Select("select * from t_user where user_name=#{userName} and password=#{password}")
@Results({
@Result(column = "user_id", property = "userId"),
@Result(column = "user_name", property = "userName"),
@Result(column = "password", property = "password"),
@Result(column = "password_assisted", property = "passwordAssisted")
})
List<UserEntity> getUserInfo(@Param("userName") String userName, @Param("password") String password);
}
1.5、測試類
@Slf4j
@SpringBootTest
class ShardingSphereDemo8ApplicationTests {
@Resource
private UserMapper userMapper;
@Test
void insertUser() {
UserEntity userEntity = new UserEntity();
userEntity.setUserId(19);
userEntity.setUserName("user19");
userEntity.setPassword("123456");
userMapper.insertUser(userEntity);
}
@Test
void getUserInfo() {
List<UserEntity> userEntityList = userMapper.getUserInfo("user19", "123456");
log.info(userEntityList.toString());
}
}
2、默認加密算法
2.1、AES
配置文件
# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用AES對稱加密策略
spring.shardingsphere.encrypt.encryptors.encryptor_aes.type=aes
spring.shardingsphere.encrypt.encryptors.encryptor_aes.props.aes.key.value=123456
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_aes
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true
測試結果
1、設置了明文列和密文列,運行成功,新增時邏輯列會改寫成明文列和密文列
2、僅設置明文列,運行直接報錯,所以必須設置加密列
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'encryptDataSource' defined in class path resource [org/apache/shardingsphere/shardingjdbc/spring/boot/SpringBootConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'encryptDataSource' threw exception; nested exception is java.lang.IllegalArgumentException: Invalid encrypt column configurations in EncryptTableRuleConfigurations.
3、僅設置密文列,運行成功,明文會進行加密,數據庫實際插入到密文列
4、設置了明文列和密文列, spring.shardingsphere.props.query.with.cipher.column 為false時,查詢通過明文列執行,返回數據為明文列
5、設置了明文列和密文列, spring.shardingsphere.props.query.with.cipher.column 為true時,查詢通過密文列查詢,返回數據為明文
6、僅設置密文列, spring.shardingsphere.props.query.with.cipher.column 為false時,查詢默認通過密文列查詢,但入參未進行自動加密,所以不能查到數據
7、僅設置密文列, spring.shardingsphere.props.query.with.cipher.column 為true時,查詢通過密文列查詢,返回數據為明文
2.2、MD5
配置文件
# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用MD5加密策略
spring.shardingsphere.encrypt.encryptors.encryptor_md5.type=MD5
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_md5
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true
測試結果
1、新增時,可以看到加密后的數據和AES的有所區別
2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過密文列查詢,由於MD5加密是非對稱的,所以返回的是密文數據
3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,返回明文數據
3、SPI自定義加密算法
3.1、SPI 配置
在resources/META-INF/services目錄下新增配置
配置文件名字為:org.apache.shardingsphere.encrypt.strategy.spi.Encryptor
配置文件里的內容,放入自定義的加密策略的類的全路徑,和要使用官方內置的加密策略的類的全路徑
org.apache.shardingsphere.encrypt.strategy.impl.AESEncryptor
org.apache.shardingsphere.encrypt.strategy.impl.MD5Encryptor
cn.zwqh.shardingspheredemo8.encryptor.Sha256Encryptor
cn.zwqh.shardingspheredemo8.encryptor.Sha256RandomEncryptor
3.2、實現Encryptor接口
創建 Sha256Encryptor 類
@Getter
@Setter
public class Sha256Encryptor implements Encryptor {
private Properties properties = new Properties();
@Override
public void init() {
}
@Override
public String encrypt(Object plaintext) {
if (null == plaintext) {
return null;
}
return DigestUtils.sha256Hex(String.valueOf(plaintext));
}
@Override
public Object decrypt(String ciphertext) {
return ciphertext;
}
@Override
public String getType() {
return "SHA256";
}
}
修改配置文件
# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用自定義策略 SHA256
spring.shardingsphere.encrypt.encryptors.encryptor_sha256.type=SHA256
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_sha256
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true
測試結果
1、新增時,可以看到加密后的數據和AES的有所區別,說明自定義加密策略使用成功
2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過密文列查詢,由於SHA256類似MD5加密,所以返回的是密文數據
3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,返回明文數據
3.3、實現QueryAssistedEncryptor接口
創建 Sha256RandomEncryptor 類
@Getter
@Setter
public class Sha256RandomEncryptor implements QueryAssistedEncryptor {
private Properties properties = new Properties();
@Override
public String queryAssistedEncrypt(String plaintext) {
if (null == plaintext) {
return null;
}
// 原始字符串
return DigestUtils.sha256Hex(String.valueOf(plaintext));
}
@Override
public void init() {
}
@Override
public String encrypt(Object plaintext) {
if (null == plaintext) {
return null;
}
// 原始字符串+變動因子(如時間戳)
plaintext = plaintext.toString() + LocalDateTime.now().toString();
return DigestUtils.sha256Hex(String.valueOf(plaintext));
}
@Override
public Object decrypt(String ciphertext) {
return ciphertext;
}
@Override
public String getType() {
return "SHA256_RANDOM";
}
}
修改配置文件
# 應用名稱
spring.application.name=sharding-sphere-demo-8
spring.shardingsphere.datasource.name=ds
spring.shardingsphere.datasource.ds.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds.url=jdbc:mysql://127.0.0.1:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds.username=root
spring.shardingsphere.datasource.ds.password=123456
spring.shardingsphere.datasource.ds.max-total=100
# 采用自定義策略 SHA256_RANDOM
spring.shardingsphere.encrypt.encryptors.encryptor_sha256_random.type=SHA256_RANDOM
# password為邏輯列,password為數據表明文列,password_encrypt為數據表密文列,password_assisted輔助查詢列
spring.shardingsphere.encrypt.tables.t_user.columns.password.plainColumn=password
spring.shardingsphere.encrypt.tables.t_user.columns.password.cipherColumn=password_encrypt
spring.shardingsphere.encrypt.tables.t_user.columns.password.assistedQueryColumn=password_assisted
spring.shardingsphere.encrypt.tables.t_user.columns.password.encryptor=encryptor_sha256_random
spring.shardingsphere.props.sql.show=true
# 查詢是否使用密文列
spring.shardingsphere.props.query.with.cipher.column=true
測試結果
1、新增兩條用戶數據,密碼一致,可以看到密文列的數據是不一致的,輔助列的數據一致,這樣可以更好的保護數據安全
2、查詢時,spring.shardingsphere.props.query.with.cipher.column為true時,通過輔助查詢列查詢,而返回的數據為密文列
3、查詢時,spring.shardingsphere.props.query.with.cipher.column為false時,通過明文列查詢,而返回的數據為明文
小結
1、數據加密默認算法支持 AES 和 MD5 兩種,AES 為對稱加密,MD5 為非對稱加密;
2、可以通過 SPI 自定義實現加密策略;
3、根據業務安全需求選擇合適的加密算法以及配置。