🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 SpringBoot 自动装配原理请看: SpringBoot自动装配原理详解!结合源代码讲解!
其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等
如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning
一、数据脱敏的定义
数据脱敏,也称为数据屏蔽、数据变形,是指对某些敏感数据通过脱敏规则进行转换,使其不再是原始的、真实的敏感数据,从而保护数据的安全性。简单来说,就是把一些敏感信息“伪装”起来 🎭,让别人看不到真实的内容,但还能保证数据在一定程度上可用。
为什么要脱敏?
- 保护隐私 🔒:避免个人信息泄露,如姓名、身份证号、手机号、银行卡号等。
- 数据安全 🛡️:防止内部人员或外部攻击者获取敏感数据,造成损失。
- 合规要求 ✅:满足法律法规对数据保护的要求,如《网络安全法》、《个人信息保护法》等。
- 测试环境 🧪:在测试、开发环境中,使用脱敏后的数据,避免真实数据泄露。
二、常用的脱敏规则
脱敏规则有很多种,选择哪种取决于数据的类型、敏感程度和业务需求。下面是一些常见的规则:
-
替换(Replacement): 用固定的字符或字符串替换原始数据。
- 例如:将手机号中间四位替换为
****
,变成138****1234
。
- 例如:将手机号中间四位替换为
-
遮蔽(Masking): 用特定的字符遮盖部分数据。
- 例如:将身份证号的前几位和后几位保留,中间用
*
遮盖。
- 例如:将身份证号的前几位和后几位保留,中间用
-
截断(Truncation): 删除部分数据。
- 例如:只显示用户名的前几个字符。
-
加密(Encryption): 使用加密算法对数据进行加密,需要时再解密。
- 例如:对银行卡号进行加密存储。
-
哈希(Hashing): 使用哈希算法将数据转换为不可逆的哈希值。
- 例如:对密码进行哈希存储。
-
随机化(Randomization): 用随机生成的数据替换原始数据。
- 例如:随机生成一个年龄或地址。
-
偏移(Shifting): 对数值型数据进行偏移。
- 例如:将所有年龄都加上或减去一个固定的值。
-
泛化(Generalization): 将数据归类到更广泛的类别。
- 例如:将具体的职业替换为职业类别(如:程序员 -> IT从业者)。
-
空值化(Nulling): 将数据设置为空值。
- 例如:如果某些数据不需要使用,可以直接设置为空。
三、常见脱敏工具及代码实例
下面介绍一些常用的Java脱敏工具,并给出代码示例。
-
Hutool
Hutool是一个Java工具包,提供了很多实用的工具类,包括脱敏工具。
import cn.hutool.core.util.DesensitizedUtil; public class HutoolExample { public static void main(String[] args) { String mobilePhone = "13812345678"; String idCard = "320101199001011234"; String address = "北京市海淀区中关村大街1号"; String desensitizedMobile = DesensitizedUtil.mobilePhone(mobilePhone); String desensitizedIdCard = DesensitizedUtil.idCardNum(idCard, 3, 4); // 保留前3位和后4位 String desensitizedAddress = DesensitizedUtil.address(address, 3); // 保留前3位 System.out.println("脱敏后的手机号: " + desensitizedMobile); // 输出:138****5678 System.out.println("脱敏后的身份证号: " + desensitizedIdCard); // 输出:320***********1234 System.out.println("脱敏后的地址: " + desensitizedAddress); // 输出:北京市海淀区*** } }
解释: Hutool就像一个工具箱 🧰,里面有各种各样的工具,其中有一个专门用来给数据“化妆”的工具 💄,可以轻松地把手机号、身份证号、地址等敏感信息处理一下。
-
ShardingSphere
ShardingSphere是一个分布式数据库中间件,它也提供了数据脱敏的功能,主要用于数据库层面的脱敏。 ShardingSphere的脱敏功能通常配置在数据分片规则中,可以对查询结果进行脱敏。
注意: ShardingSphere的脱敏配置比较复杂,需要定义脱敏算法,并将其应用到特定的表和列上。 以下是一个简化的概念示例,实际配置需要参考ShardingSphere的官方文档。
<!-- ShardingSphere脱敏配置 (简化示例) --> <bean id="shardingRuleConfiguration" class="org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration"> <property name="tables"> <map> <entry key="t_user"> <bean class="org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration"> <property name="logicTable" value="t_user"/> <property name="actualDataNodes" value="ds0.t_user,ds1.t_user"/> <property name="tableStrategyConfig"> <bean class="org.apache.shardingsphere.sharding.api.config.strategy.StandardShardingStrategyConfiguration"> <constructor-arg name="shardingColumn" value="user_id"/> <constructor-arg name="shardingAlgorithmName" value="inlineTableShardingAlgorithm"/> </bean> </property> <property name="keyGeneratorConfig"> <bean class="org.apache.shardingsphere.sharding.api.config.KeyGeneratorConfiguration"> <constructor-arg name="type" value="SNOWFLAKE"/> <constructor-arg name="column" value="user_id"/> </bean> </property> <property name="encryptRule"> <bean class="org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration"> <property name="encryptors"> <map> <entry key="mobile_encryptor"> <bean class="org.apache.shardingsphere.encrypt.api.config.EncryptorRuleConfiguration"> <constructor-arg name="type" value="AES"/> <constructor-arg name="properties"> <map> <entry key="aes.key.value" value="your_aes_key"/> </map> </constructor-arg> </bean> </entry> </map> </property> <property name="tables"> <map> <entry key="t_user"> <bean class="org.apache.shardingsphere.encrypt.api.config.EncryptTableRuleConfiguration"> <property name="columns"> <map> <entry key="mobile"> <bean class="org.apache.shardingsphere.encrypt.api.config.EncryptColumnRuleConfiguration"> <constructor-arg name="cipherColumn" value="mobile_cipher"/> <constructor-arg name="encryptorName" value="mobile_encryptor"/> </bean> </entry> </map> </property> </bean> </entry> </map> </property> </bean> </property> </bean> </entry> </map> </property> <property name="defaultDatabaseStrategyConfig"> <bean class="org.apache.shardingsphere.sharding.api.config.strategy.StandardShardingStrategyConfiguration"> <constructor-arg name="shardingColumn" value="database_id"/> <constructor-arg name="shardingAlgorithmName" value="inlineDatabaseShardingAlgorithm"/> </bean> </property> <property name="shardingAlgorithms"> <map> <entry key="inlineTableShardingAlgorithm"> <bean class="org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingAlgorithm"> <property name="expression" value="t_user_${user_id % 2}"/> </bean> </entry> <entry key="inlineDatabaseShardingAlgorithm"> <bean class="org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingAlgorithm"> <property name="expression" value="ds${database_id % 2}"/> </bean> </entry> </map> </property> </bean>
解释: ShardingSphere就像一个数据库的“管家” 🤵,它可以把数据分到不同的地方存储,还能在别人访问数据的时候,自动把敏感信息“处理”一下,比如加密或者替换掉。 配置比较复杂 ⚙️,需要告诉它哪些数据需要脱敏,用什么方法脱敏。
-
Fastjson
Fastjson是阿里巴巴开源的JSON处理库,虽然它本身没有直接的脱敏功能,但可以通过自定义序列化器来实现脱敏。
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.serializer.ValueFilter; public class FastjsonExample { public static class User { private String name; @JSONField(serializeUsing = MobilePhoneDesensitization.class) private String mobilePhone; private String address; public User(String name, String mobilePhone, String address) { this.name = name; this.mobilePhone = mobilePhone; this.address = address; } public String getName() { return name; } public String getMobilePhone() { return mobilePhone; } public String getAddress() { return address; } } // 自定义序列化器 public static class MobilePhoneDesensitization implements ValueFilter { @Override public Object process(Object object, String name, Object value) { if ("mobilePhone".equals(name) && value instanceof String) { String mobile = (String) value; if (mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } } return value; } } public static void main(String[] args) { User user = new User("张三", "13812345678", "北京市海淀区"); String json = JSON.toJSONString(user); System.out.println(json); // 输出:{"address":"北京市海淀区","mobilePhone":"138****5678","name":"张三"} // 使用ValueFilter进行全局脱敏 ValueFilter filter = (Object object, String name, Object value) -> { if ("address".equals(name) && value instanceof String) { return "***"; // 对所有address字段进行脱敏 } return value; }; String jsonWithFilter = JSON.toJSONString(user, filter); System.out.println(jsonWithFilter); // 输出:{"address":"***","mobilePhone":"138****5678","name":"张三"} } }
解释: Fastjson就像一个翻译器 🗣️,可以把Java对象翻译成JSON字符串。我们可以告诉它,在翻译手机号的时候,要先给手机号“化个妆” 💄,把中间几位换成星星 ⭐。
-
MyBatis-Flex
MyBatis-Flex 是一个优雅的 MyBatis 增强框架,它提供了灵活的配置方式,可以方便地实现数据脱敏。
import com.mybatisflex.annotation.Column; import com.mybatisflex.annotation.Table; import com.mybatisflex.core.handler.AbstractTypeHandler; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.mapper.BaseMapper; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedTypes; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; // 自定义 TypeHandler @MappedTypes(String.class) public class MobilePhoneTypeHandler extends AbstractTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // 保存到数据库时,可以进行加密等处理 ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { String mobile = rs.getString(columnName); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String mobile = rs.getString(columnIndex); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String mobile = cs.getString(columnIndex); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } } // 实体类 @Table("tb_user") public static class User { private Long id; private String name; @Column(typeHandler = MobilePhoneTypeHandler.class) private String mobilePhone; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMobilePhone() { return mobilePhone; } public void setMobilePhone(String mobilePhone) { this.mobilePhone = mobilePhone; } } // Mapper 接口 public interface UserMapper extends BaseMapper<User> { } // 使用示例 public class MyBatisFlexExample { public static void main(String[] args) { // 假设已经配置好了 MyBatis-Flex UserMapper userMapper = null; // 获取 UserMapper 实例 // 查询用户 User user = userMapper.selectOneById(1L); System.out.println("脱敏后的手机号: " + user.getMobilePhone()); // 插入用户 User newUser = new User(); newUser.setName("李四"); newUser.setMobilePhone("13912345678"); userMapper.insert(newUser); } }
解释: MyBatis-Flex 就像一个数据库的“翻译官” 🧑🏫,它可以把数据库里的数据翻译成Java对象。我们可以自定义一个“翻译规则” 📜,告诉它在翻译手机号的时候,要先给手机号“化个妆” 💄,把中间几位换成星星 ⭐。
-
Mybatis-Mate
Mybatis-Mate 是一款基于 MyBatis 的代码生成器和增强工具,它也支持自定义 TypeHandler 来实现数据脱敏。
import net.dreamlu.mica.mybatis.typehandler.AbstractTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedTypes; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; // 自定义 TypeHandler @MappedTypes(String.class) public class MobilePhoneTypeHandler extends AbstractTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // 保存到数据库时,可以进行加密等处理 ps.setString(i, parameter); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { String mobile = rs.getString(columnName); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String mobile = rs.getString(columnIndex); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String mobile = cs.getString(columnIndex); if (mobile != null && mobile.length() == 11) { return mobile.substring(0, 3) + "****" + mobile.substring(7); } return mobile; } } // 实体类 public class User { private Long id; private String name; private String mobilePhone; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMobilePhone() { return mobilePhone; } public void setMobilePhone(String mobilePhone) { this.mobilePhone = mobilePhone; } } // 使用示例 (假设已经配置好了 Mybatis-Mate) public class MybatisMateExample { public static void main(String[] args) { // 获取 User 对象 User user = null; // 从数据库查询得到 User 对象 // 在获取 mobilePhone 属性时,会自动进行脱敏 String desensitizedMobile = user.getMobilePhone(); System.out.println("脱敏后的手机号: " + desensitizedMobile); } }
解释: Mybatis-Mate 也是一个数据库的“翻译官” 🧑🏫,和 MyBatis-Flex 类似,它可以把数据库里的数据翻译成Java对象。我们可以自定义一个“翻译规则” 📜,告诉它在翻译手机号的时候,要先给手机号“化个妆” 💄,把中间几位换成星星 ⭐。
完整的Hutool实例,包含依赖和测试:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.23</version>
</dependency>
import cn.hutool.core.util.DesensitizedUtil;
public class HutoolExample {
public static void main(String[] args) {
String mobilePhone = "13812345678";
String idCard = "320101199001011234";
String address = "北京市海淀区中关村大街1号";
String email = "test@example.com";
String bankCard = "6222020000000000";
String desensitizedMobile = DesensitizedUtil.mobilePhone(mobilePhone);
String desensitizedIdCard = DesensitizedUtil.idCardNum(idCard, 3, 4); // 保留前3位和后4位
String desensitizedAddress = DesensitizedUtil.address(address, 3); // 保留前3位
String desensitizedEmail = DesensitizedUtil.email(email);
String desensitizedBankCard = DesensitizedUtil.bankCard(bankCard);
System.out.println("脱敏后的手机号: " + desensitizedMobile); // 输出:138****5678
System.out.println("脱敏后的身份证号: " + desensitizedIdCard); // 输出:320***********1234
System.out.println("脱敏后的地址: " + desensitizedAddress); // 输出:北京市海淀区***
System.out.println("脱敏后的邮箱: " + desensitizedEmail); // 输出:t**@example.com
System.out.println("脱敏后的银行卡号: " + desensitizedBankCard); // 输出:622202********0000
}
}
四、总结
- Hutool 适合在代码中对单个数据进行脱敏,使用简单方便 🚀。
- ShardingSphere 适合在数据库层面进行脱敏,可以对查询结果进行脱敏,但配置比较复杂 ⚙️。
- Fastjson 可以通过自定义序列化器来实现脱敏,适合在JSON序列化时进行脱敏 💡。
- MyBatis-Flex 和 Mybatis-Mate 可以通过自定义 TypeHandler 来实现数据库字段的脱敏,适合在数据访问层进行脱敏 📚。
选择哪种工具取决于你的具体需求和使用场景 🤔。 希望篇文章能够帮助你理解数据脱敏的概念和常用工具 🎉。