We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在实际的业务场景中,业务开发团队需要针对公司安全部门需求,针对涉及客户安全数据或者一些商业性敏感数据,如身份证号、手机号、银行卡号、客户号等个人信息,都需要进行数据脱敏。
搭建和生产环境一模一样的预发布环境,需要把生产环境的存量原文数据 加密后存储到预发环境。
目前常见的脱敏算法包括 AES 加密、K 匿名、加星、屏蔽、洗牌、全保留、格式保留、令牌化等,算法及其主要用途介绍如下:
目前 Java 生态环境下,数据脱敏中间件这块,做的最好的应该数 ShardingSphere,引用 ShardingSphere 官方文档关于数据脱敏模块的说明:
数据脱敏模块属于ShardingSphere分布式治理这一核心功能下的子功能模块。它通过对用户输入的SQL进行解析,并依据用户提供的脱敏配置对SQL进行改写,从而实现对原文数据进行加密,并将原文数据(可选)及密文数据同时存储到底层数据库。在用户查询数据时,它又从数据库中取出密文数据,并对其解密,最终将解密后的原始数据返回给用户。
更多关于 ShardingSphere 的数据脱敏原理,可以查阅官方文档。
那如果说,我只是想简单的做一些数据清洗和隐私脱敏,有什么的好的工具类吗?那可以使用 hutool 的 DesensitizedUtil 工具类就行,例如:
String phone = "13488883888"; String encryptPhone = DesensitizedUtil.mobilePhone(phone); // 打印:134****3888 System.out.println(encryptPhone);
在 ShardingSphere 的关于数据脱敏的场景分析里,针对已上线的历史数据,需要业务方自己进行清洗。那怎么清洗?简单说下自己的想法:
首先数据库对那些需要脱敏的列,新增额外的加密列,比如需要对 email进行脱敏,则新建额外的加密列 encrypt_email。
系统接入 sharding-jdbc,并配置好脱敏规则。
写个脚本,多线程同时遍历需要脱敏的历史数据,将明文列(email)取出,更新到加密列(encrypt_email),由于sharding-jdbc 会根据脱敏规则,对SQL进行解析、改写,最后加密列存储的其实是加密后的数据。
这里将使用 ShardingSphere 的 sharding-jdbc 组件简单的演示如何进行数据脱敏。
user 表结构,其中 email 为明文列,encrypt_email 为密文列。
CREATE TABLE `user` ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名', `age` int unsigned NOT NULL COMMENT '年龄', `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '明文邮箱 ', `encrypt_email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '加密邮箱', PRIMARY KEY (`id`), UNIQUE KEY `uk_email` (`email`) USING BTREE COMMENT '邮箱唯一索引' ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
这里只展示 sharding-jdbc 的配置部分:
spring: # sharding-jdbc配置 shardingsphere: # 数据源配置 datasource: name: ds ds: driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://127.0.0.1:3306/shardingsphere?useUnicode=true&useSSL=true&characterEncoding=utf8 username: root password: '123456' max-total: 100 encrypt: # 加密器配置 encryptors: # 加密器的名字,这里设置为:email_encryptor email_encryptor: # 加密方式,内置MD5/AES type: aes props: # 配置AES加密器的KEY属性 aes.key.value: 123456abc # 脱敏表配置 tables: # 脱敏表名 user: columns: # 脱敏逻辑列,真实面向用户编写SQL email: # 存储明文列 plainColumn: email # 存储加密列 cipherColumn: encrypt_email # 使用的加密器 encryptor: email_encryptor props: # 是否使用密文列查询 query.with.cipher.column: true # 是否打印SQL,默认false sql.show: true
由于使用 ShardingSphere 的数据源 datasource 后,无需再配置 Spring 自带的 datasource,另外遇到个小问题就是,如果按照 ShardingSphere 官方关于数据脱敏的 springboot配置(官网示例 properties 格式,实际也可以转成yml 格式):
url: jdbc:mysql://127.0.0.1:3306/shardingsphere?useUnicode=true&useSSL=true&characterEncoding=utf8
会报错 jdbcUrl is required with driverClassName,换成 jdbc-url 则正常启动:
jdbcUrl is required with driverClassName
jdbc-url
jdbc-url: jdbc:mysql://127.0.0.1:3306/shardingsphere?useUnicode=true&useSSL=true&characterEncoding=utf8
插入一条数据:
userService.save(new User("韩武江", 28, "[email protected]"));
观察控制台打印的两条log:
# 逻辑SQL Logic SQL: INSERT INTO user ( name,age,email ) VALUES ( ?,?,? ) # 实际SQL Actual SQL: ds ::: INSERT INTO user ( name,age,encrypt_email, email ) VALUES (?, ?, ?, ?) ::: [韩武江, 28, dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=, hanwujiang@163.com]
再观察数据库:
加密列 encrypt_email 被 sharding-jdbc 加密存储。
查询数据,并设置 query.with.cipher.column: true,开启密文列查询:
query.with.cipher.column: true
User user = userService.getByEmail("[email protected]"); System.out.println(JSONUtil.toJsonStr(user));
观察控制台打印的log:
# 逻辑SQL Logic SQL: SELECT id,name,age,email,encrypt_email FROM user WHERE email=? # 实际SQL Actual SQL: ds ::: SELECT id,name,age,encrypt_email AS email,encrypt_email FROM user WHERE encrypt_email=? ::: [dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=] # 打印结果 {"encryptEmail":"dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=","name":"韩武江","id":13,"age":28,"email":"[email protected]"}
若设置query.with.cipher.column: false,关闭密文列查询:
query.with.cipher.column: false
# 逻辑SQL Logic SQL: SELECT id,name,age,email,encrypt_email FROM user WHERE email=? # 实际SQL Actual SQL: ds ::: SELECT id,name,age,email AS email,encrypt_email FROM user WHERE email=? ::: [hanwujiang@163.com] # 打印结果 {"encryptEmail":"dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=","name":"韩武江","id":13,"age":28,"email":"[email protected]"}
我原本以为在开启密文查询的情况,实际SQL都 encrypt_email AS email了,最终返回实体里面的email应该是密文:
encrypt_email AS email
SELECT id, `name`, age, encrypt_email AS email, encrypt_email FROM `user` WHERE encrypt_email = 'dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=';
但是对比可以发现,开启密文列查询配置后,实际sharding-jdbc会在中间把密文解密后返回,最终返回实体里面的email应该是解密后的明文,密文存在的还是在密文列 encrypt_email 中。
假如后期业务上线一段时间后,需要完全删除明文列,只保留密文列,在不改变代码的基础上是否可行?那直接在数据库层,把email列删除:
然后修改 sharding-jdbc 配置,去掉明文列,不改写任何其他代码层面的东西:
# 脱敏表配置 tables: user: columns: email: # plainColumn: email cipherColumn: encrypt_email encryptor: email_encryptor
然后查询数据:
// 为了演示,这里改用id查询,如果用email查询的话,肯定为空 User user = userService.getById(13); System.out.println(JSONUtil.toJsonStr(user));
观察控制台,发现其实依然能正常执行,且不报错:
# 逻辑SQL Logic SQL: SELECT id,name,age,email,encrypt_email FROM user WHERE id=? # 实际SQL Actual SQL: ds ::: SELECT id,name,age,encrypt_email AS email,encrypt_email FROM user WHERE id=? ::: [13] # 打印结果 {"encryptEmail":"dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M=","name":"韩武江","id":13,"age":28,"email":"dad+OyyGMYILeBGwiWHU+tmzk4uJ7CCz4mB1va9Ya1M="}
至于为什么会正常运行,因为:
因为有logicColumn存在,用户的编写SQL都面向这个虚拟列,Encrypt-JDBC就可以把这个逻辑列和底层数据表中的密文列进行映射转换
假如你删除 email列,但是配置中还配置了 plainColumn: email,那代码执行的时候,则会报错:Cause: java.sql.SQLSyntaxErrorException: Unknown column 'email' in 'field list'。
plainColumn: email
Cause: java.sql.SQLSyntaxErrorException: Unknown column 'email' in 'field list'
我个人的感觉是 sharding-jdbc 确实做到了屏蔽底层对数据的脱敏处理 ,但是要接入 sharding-jdbc 的前提是,团队有制定严格的SQL规范 ,这样可能接入数据库中间件的时候,才会出现比较少的问题,对于一些老系统,动辄几百行的SQL,各种复杂函数,还是放弃接入的好,到时候只会是一步一个坑。
另外如果想要满足文章开头的第二个需求,也就是把生产库的数据同步到预发布,同时要屏蔽部分敏感数据,大部分的云厂商,都有提供脱敏工具,比如我们自己在用的腾讯云的 DBbrain,就可以支持数据脱敏,但是实际使用还不是怎么完善,有待改进。
示例代码:shardingsphere-encrypt-jdbc-demo
The text was updated successfully, but these errors were encountered:
superleeyom
No branches or pull requests
业务数据脱敏解决方案探究
使用背景
在实际的业务场景中,业务开发团队需要针对公司安全部门需求,针对涉及客户安全数据或者一些商业性敏感数据,如身份证号、手机号、银行卡号、客户号等个人信息,都需要进行数据脱敏。
搭建和生产环境一模一样的预发布环境,需要把生产环境的存量原文数据 加密后存储到预发环境。
技术调研
常见的脱敏算法
目前常见的脱敏算法包括 AES 加密、K 匿名、加星、屏蔽、洗牌、全保留、格式保留、令牌化等,算法及其主要用途介绍如下:
Java生态下的脱敏方案
目前 Java 生态环境下,数据脱敏中间件这块,做的最好的应该数 ShardingSphere,引用 ShardingSphere 官方文档关于数据脱敏模块的说明:
更多关于 ShardingSphere 的数据脱敏原理,可以查阅官方文档。
那如果说,我只是想简单的做一些数据清洗和隐私脱敏,有什么的好的工具类吗?那可以使用 hutool 的 DesensitizedUtil 工具类就行,例如:
技术演练
在 ShardingSphere 的关于数据脱敏的场景分析里,针对已上线的历史数据,需要业务方自己进行清洗。那怎么清洗?简单说下自己的想法:
首先数据库对那些需要脱敏的列,新增额外的加密列,比如需要对 email进行脱敏,则新建额外的加密列 encrypt_email。
系统接入 sharding-jdbc,并配置好脱敏规则。
写个脚本,多线程同时遍历需要脱敏的历史数据,将明文列(email)取出,更新到加密列(encrypt_email),由于sharding-jdbc 会根据脱敏规则,对SQL进行解析、改写,最后加密列存储的其实是加密后的数据。
这里将使用 ShardingSphere 的 sharding-jdbc 组件简单的演示如何进行数据脱敏。
数据库结构
user 表结构,其中 email 为明文列,encrypt_email 为密文列。
配置解析
这里只展示 sharding-jdbc 的配置部分:
由于使用 ShardingSphere 的数据源 datasource 后,无需再配置 Spring 自带的 datasource,另外遇到个小问题就是,如果按照 ShardingSphere 官方关于数据脱敏的 springboot配置(官网示例 properties 格式,实际也可以转成yml 格式):
会报错
jdbcUrl is required with driverClassName
,换成jdbc-url
则正常启动:实验对比
插入一条数据:
观察控制台打印的两条log:
再观察数据库:
加密列 encrypt_email 被 sharding-jdbc 加密存储。
查询数据,并设置
query.with.cipher.column: true
,开启密文列查询:观察控制台打印的log:
若设置
query.with.cipher.column: false
,关闭密文列查询:观察控制台打印的log:
我原本以为在开启密文查询的情况,实际SQL都
encrypt_email AS email
了,最终返回实体里面的email应该是密文:但是对比可以发现,开启密文列查询配置后,实际sharding-jdbc会在中间把密文解密后返回,最终返回实体里面的email应该是解密后的明文,密文存在的还是在密文列 encrypt_email 中。
假如后期业务上线一段时间后,需要完全删除明文列,只保留密文列,在不改变代码的基础上是否可行?那直接在数据库层,把email列删除:
然后修改 sharding-jdbc 配置,去掉明文列,不改写任何其他代码层面的东西:
然后查询数据:
观察控制台,发现其实依然能正常执行,且不报错:
至于为什么会正常运行,因为:
假如你删除 email列,但是配置中还配置了
plainColumn: email
,那代码执行的时候,则会报错:Cause: java.sql.SQLSyntaxErrorException: Unknown column 'email' in 'field list'
。总结
我个人的感觉是 sharding-jdbc 确实做到了屏蔽底层对数据的脱敏处理 ,但是要接入 sharding-jdbc 的前提是,团队有制定严格的SQL规范 ,这样可能接入数据库中间件的时候,才会出现比较少的问题,对于一些老系统,动辄几百行的SQL,各种复杂函数,还是放弃接入的好,到时候只会是一步一个坑。
另外如果想要满足文章开头的第二个需求,也就是把生产库的数据同步到预发布,同时要屏蔽部分敏感数据,大部分的云厂商,都有提供脱敏工具,比如我们自己在用的腾讯云的 DBbrain,就可以支持数据脱敏,但是实际使用还不是怎么完善,有待改进。
示例代码:shardingsphere-encrypt-jdbc-demo
The text was updated successfully, but these errors were encountered: