什么是数据脱敏
数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。数据脱敏可以分为静态数据脱敏和动态数据脱敏,其中静态数据脱敏一般应用于数据外发场景,例如需要将数据导出发送给开发人员、测试人员等,静态数据脱敏会将变化后的数据进行保存,供数据使用方使用;动态数据脱敏一般应用于直接连接生产数据的场景,例如运维人员直接连接生产数据库进行运维,动态数据脱敏会在数据获取过程中对数据进行变化处理,不会修改原始数据。
思路
使用Java类进行数据脱敏的思路主要围绕几个关键步骤,以确保敏感信息在不被授权的情况下不被泄露。以下是一个基本的脱敏思路:
- 定义脱敏规则:
- 首先,需要明确哪些数据是敏感的,例如身份证号、手机号、银行卡号、邮箱地址等。
- 对于每种敏感数据,定义相应的脱敏规则。例如,对于手机号,可能只保留前三位和后四位,中间用星号(*)替换;对于身份证号,可能只保留前几位和后几位,中间用星号替换。
- 创建脱敏工具类:
- 编写一个Java类,该类包含多个静态方法,每个方法对应一种敏感数据的脱敏逻辑。
- 这些方法通常接受一个字符串参数(即待脱敏的敏感数据),并返回一个脱敏后的字符串。
- 实现脱敏逻辑:
- 在脱敏工具类中,根据定义的脱敏规则实现具体的脱敏逻辑。
- 可以使用字符串操作函数(如
substring
、replace
等)和正则表达式来实现复杂的脱敏需求。 - 如果需要,还可以集成加密算法(如AES、DES等)来实现更高级别的脱敏。
- 调用脱敏工具类:
- 在需要脱敏的地方(如数据库查询、日志记录、接口返回等),调用脱敏工具类中的相应方法来进行脱敏处理。
- 可以将脱敏逻辑封装在业务逻辑层或数据访问层中,以便在数据被返回给前端或存储到日志之前进行脱敏。
- 测试与验证:
- 编写测试用例来验证脱敏工具类的正确性。
- 确保在各种情况下(如空值、异常输入等)都能得到正确的脱敏结果。
- 扩展与配置:
- 根据实际需求,可以扩展脱敏工具类以支持更多的敏感数据类型和脱敏规则。
- 可以将脱敏规则配置在外部配置文件中(如properties文件、YAML文件等),以便在不修改代码的情况下修改脱敏规则。
- 动态数据脱敏(可选):
- 如果需要在生产环境中对实时访问的敏感数据进行脱敏处理(即动态数据脱敏),可以考虑使用数据库中间件或ORM框架的拦截器来实现。
- 这些中间件或拦截器可以在数据被查询出来并返回给客户端之前进行脱敏处理。
需要注意的是,数据脱敏只是数据保护的一个方面。在实际应用中,还需要结合其他安全措施(如访问控制、加密存储等)来确保数据的安全性和隐私性。
Java实现
引入依赖
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--json模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
创建注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationSerialize.class)
public @interface Desensitization {
/**
* 脱敏数据类型,只要在CUSTOMER的时候,startInclude和endExclude生效
*/
DesensitizationTypeEnum type() default DesensitizationTypeEnum.CUSTOMER;
/**
* 开始位置(包含)
*/
int startInclude() default 0;
/**
* 结束位置(不包含)
*/
int endExclude() default 0;
}
添加枚举类
public enum DesensitizationTypeEnum {
//自定义
CUSTOMER,
//中文名
CHINESE_NAME,
//身份证号
ID_CARD,
//手机号
MOBILE_PHONE,
//地址
ADDRESS,
//电子邮件
EMAIL,
//中国大陆车牌,包含普通车辆、新能源车辆
CAR_LICENSE,
//银行卡
BANK_CARD
}
自定义脱敏序列化类
@NoArgsConstructor
@AllArgsConstructor
public class DesensitizationSerialize extends JsonSerializer<String> implements ContextualSerializer {
private DesensitizationTypeEnum type;
private Integer startInclude;
private Integer endExclude;
@Override
public void serialize(String str, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
switch (type) {
//自定义 Java 对象如何序列化成 JSON 格式
// 自定义类型脱敏
case CUSTOMER:
//通过使用 CharSequenceUtil 类,开发者可以更加方便地进行字符串相关的编程工作,避免了重复编写基础的字符串处理逻辑
jsonGenerator.writeString(CharSequenceUtil.hide(str,startInclude,endExclude));
break;
// 中文姓名脱敏
case CHINESE_NAME:
jsonGenerator.writeString(DesensitizedUtil.chineseName(String.valueOf(str)));
break;
// 身份证脱敏
case ID_CARD:
jsonGenerator.writeString(DesensitizedUtil.fixedPhone(String.valueOf(str)));
break;
// 手机号脱敏
case MOBILE_PHONE:
jsonGenerator.writeString(DesensitizedUtil.mobilePhone(String.valueOf(str)));
break;
// 地址脱敏
case ADDRESS:
jsonGenerator.writeString(DesensitizedUtil.address(String.valueOf(str), 8));
break;
// 邮箱脱敏
case EMAIL:
jsonGenerator.writeString(DesensitizedUtil.password(String.valueOf(str)));
break;
// 中国车牌脱敏
case CAR_LICENSE:
jsonGenerator.writeString(DesensitizedUtil.carLicense(String.valueOf(str)));
break;
// 银行卡脱敏
case BANK_CARD:
jsonGenerator.writeString(DesensitizedUtil.bankCard(String.valueOf(str)));
break;
default:
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
if (beanProperty != null) {
// 判断数据类型是否为String类型
if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
// 获取定义的注解
Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);
// 为null
if (desensitization == null) {
desensitization = beanProperty.getContextAnnotation(Desensitization.class);
}
// 不为null
if (desensitization != null) {
// 创建定义的序列化类的实例并且返回,入参为注解定义的type,开始位置,结束位置。
return new DesensitizationSerialize(desensitization.type(), desensitization.startInclude(),
desensitization.endExclude());
}
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}
添加脱敏注解
@Data
public class TestAnnotationDTO implements Serializable {
/**
* 自定义
*/
@Desensitization(type = DesensitizationTypeEnum.CUSTOMER,startInclude = 5,endExclude = 10)
private String custom;
/**
* 手机号
*/
@Desensitization(type = DesensitizationTypeEnum.MOBILE_PHONE)
private String phone;
/**
* 邮箱
*/
@Desensitization(type = DesensitizationTypeEnum.EMAIL)
private String email;
/**
* 身份证
*/
@Desensitization(type = DesensitizationTypeEnum.ID_CARD)
private String idCard;
}