对互联网公司、传统行业来说,数据安全一直是极为重视和敏感的话题。数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。涉及客户安全数据或者一些商业性敏感数据,如身份证号、手机号、卡号、地址、客户号等个人信息按照相关部门规定,都需要进行数据脱敏。
应安全审计要求,需要对数据库中的用户关键信息做加密处理,这样,即使生产数据被拖库,也不会泄露用户的敏感信息。
使用sharding-jdbc实现数据脱敏,比如:用户表中的password字段,日常开发都会进行数据脱敏,对其进行加密**。本文源代码使用Apache2.0开源协议,代码下载地址。
附:shardingsphere官网-数据脱敏介绍、shardingsphere官网-数据脱敏Yaml配置
项目的目录结构:
一、引入相关依赖
核心依赖
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC2
完整依赖
4.0.0
com.erbadagang.sharding.jdbc
sharding-jdbc-data-cipher
0.0.1-SNAPSHOT
sharding-jdbc-data-cipher
Demo project for Spring Boot
1.8
UTF-8
UTF-8
2.3.0.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
5.1.48
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.1
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC2
org.springframework
spring-aspects
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
UTF-8
org.springframework.boot
spring-boot-maven-plugin
repackage
二、 application.yml:
############################数据脱敏#################################
#服务端口
server:
port: 8080
#服务名
spring:
application:
name: sharding-jdbc-data-cipher
main:
allow-bean-definition-overriding: true
shardingsphere:
datasource: #数据源配置
names: ds
ds:
#url: jdbc:mysql://192.168.24.140:3306/test1?useSSL=false&useUnicode=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource # 使用 Hikari 数据库连接池
#driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://101.133.227.13:3306/orders_1?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: guo
password: 205010guo
encrypt:
encryptors:
encryptor_aes:
type: aes #加解密器类型,可自定义或选择内置类型:MD5/AES
props:
aes.key.value: guoxiuzhi-IA8 #属性配置, 注意:使用AES加密器,需要配置AES加密器的KEY属性:aes.key.value
qualifiedColumns: t_user.password
tables:
t_user:
columns:
password:
cipherColumn: password #存储密文的字段
encryptor: encryptor_aes #加解密器名字
props:
sql:
show: true #是否开启SQL显示,默认值: false
query:
with:
cipher:
column: true #是否使用密文列查询
三、建表语句
CREATE TABLE `orders_1`.`t_user` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`user_name` varchar(25),
`password` varchar(55),
PRIMARY KEY (`id`)
);
四、UserDao:操作数据库接口
package com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.dao;
import com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
/**
* @description dao数据接口,mybatis数据库操作类。
* @ClassName: UserDao
* @author: 郭秀志 [email protected]
* @date: 2020/7/2 15:58
* @Copyright:
*/
@Repository
public interface UserDao {
@Insert("INSERT INTO t_user (user_name,password) VALUES (#{userName}, #{password})")
void addUser(@Param("userName") String userName, @Param("password") String password);
@Select("SELECT id,user_name as userName,password FROM t_user WHERE user_name=#{userName} and password= #{password}")
User selectUser(@Param("userName") String userName, @Param("password") String password);
}
五、 User实体类 :
package com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @description 用户数据entity
* @ClassName: User
* @author: 郭秀志 [email protected]
* @date: 2020/7/2 15:57
* @Copyright:
*/
@Data
public class User implements Serializable {
private Long id;
private String userName;
private String password;
}
六、启动类
package com.erbadagang.sharding.jdbc.shardingjdbcdatacipher;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @description 项目启动类
* @ClassName: ShardingJdbcDataCipherApplication
* @author: 郭秀志 [email protected]
* @date: 2020/7/2 16:12
* @Copyright:
*/
@SpringBootApplication
@MapperScan(value = "com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.dao")
public class ShardingJdbcDataCipherApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingJdbcDataCipherApplication.class, args);
}
}
七、测试类
package com.erbadagang.sharding.jdbc.shardingjdbcdatacipher;
import com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.dao.UserDao;
import com.erbadagang.sharding.jdbc.shardingjdbcdatacipher.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @description 数据脱敏测试类,包括insert后数据库密文存储,及加密字段查询功能。
* @ClassName: ShardingJdbcDataCipherApplicationTests
* @author: 郭秀志 [email protected]
* @date: 2020/7/2 16:14
* @Copyright:
*/
@SpringBootTest
class ShardingJdbcDataCipherApplicationTests {
@Test
void contextLoads() {
}
@Autowired
private UserDao userDao;
@Test
void add() {
userDao.addUser("guo", "123456");
}
@Test
public void query() {
User user = userDao.selectUser("guo", "123456");
System.out.println(user);
}
}
八、测试结果
8.1 add()方法运行结果
2020-07-02 16:05:45.587 INFO 16188 --- [main] ShardingSphere-SQL: Rule Type: encrypt
2020-07-02 16:05:45.587 INFO 16188 --- [main] ShardingSphere-SQL: SQL: INSERT INTO t_user (user_name,password) VALUES (?, ?)
8.2 query()方法运行结果
2020-07-02 16:05:45.784 INFO 16188 --- [main] ShardingSphere-SQL: Rule Type: encrypt
2020-07-02 16:05:45.784 INFO 16188 --- [main] ShardingSphere-SQL: SQL: SELECT id,user_name as userName,password FROM t_user WHERE user_name=? and password = ?
User(id=1, userName=guo, password=123456)
九、其他特性
9.1 plainColumn保存明文的字段
application.yml改造:
tables:
t_user:
columns:
password: #logicColumn逻辑列名称
plainColumn: password #存储明文的字段
cipherColumn: pwd_cipher #存储密文的字段
encryptor: encryptor_aes #加解密器名字
新增字段的SQL语句:
ALTER TABLE `orders_1`.`t_user`
ADD COLUMN `pwd_cipher` varchar(55) AFTER `password`;
依据上述加密规则可知,首先需要在数据库表 t_user 里新增一个字段叫做 pwd_cipher
,即cipherColumn
,用于存放密文数据,同时我们把 plainColumn
设置为 password
,用于存放明文数据,而把logicColumn
也设置为password
。 由于之前的代码 SQL 就是使用 password
进行编写,即面向逻辑列进行 SQL 编写,所以业务代码无需改动。
对应的sql依旧是:
@Insert("INSERT INTO t_user (user_name,password) VALUES (#{userName}, #{password})")
void addUser(@Param("userName") String userName, @Param("password") String password);
通过 Apache ShardingSphere,针对新增的数据,会把明文写到 password
列,并同时把明文进行加密存储到pwd_cipher
列。 此时,如果 query.with.cipher.column
设置为false
,对业务应用来说,依旧使用 password
这一明文列进行查询存储,却在底层数据库表pwd_cipher
上额外存储了新增数据的密文数据。
再次运行测试,数据库中同时保存明文和密文数据: