脱敏工具
目前文档内容对标 ballcat v0.6.0 以上版本
为防止隐私或敏感数据的泄露,项目开发中经常需要对特定的数据进行脱敏处理,BallCat 为此提供了一个脱敏工具包
1. 简介
根据不同的脱敏方式,BallCat 划分出了三种脱敏类型
Simple(简单脱敏):
只需根据原始数据即可推出脱敏后的数据的处理方式。
例如简单粗暴的将数据替换为 6个* 号的处理方式:
a1234
=>******
Regex (正则脱敏):
将原始数据根据正则表达式进行替换处理。
例如邮箱处理后第一个字符和'@'之后的原文显示,中间的显示为4个*:
[email protected]
=>1****@qq.com
Slide(滑动脱敏)
根据设置的左右明文数来控制明文展示,剩余的全部替换为 *,好处在于会保留原始数据位数,提升辨析度。
例如手机号处理,明文保持前三后二:
15805516789
=>158******89
在实际使用中,可以根据需求进行额外的拓展处理
2. 依赖安装
此工具包已发布到 Maven 中央仓库,可以将以下内容添加到您的 POM 文件中以使用
<dependency>
<groupId>com.hccake</groupId>
<artifactId>ballcat-common-desensitize</artifactId>
<version>${lastVersion}</version>
</dependency>
3. 基本使用
3.1 脱敏处理器
BallCat 提供了 DesensitizationHandlerHolder
类,来对系统内的所有脱敏处理器进行归集,方便使用的时候直接获取,而不必再创建新的对象。
3.2 简单脱敏
对于简单脱敏类型,BallCat 只内置了一种脱敏处理器:SixAsteriskDesensitizationHandler
,不管原文是什么,一律返回6个 *。
使用示例:
// 获取简单脱敏处理器
SimpleDesensitizationHandler desensitizationHandler =
DesensitizationHandlerHolder.getSimpleHandler(SixAsteriskDesensitizationHandler.class);
String origin = "你好吗?"; // 原始字符串
String target = desensitizationHandler.handle(origin); // 替换处理
System.out.println(target); // 结果:******
如需定制自己的简单脱敏处理器,参看扩展使用。
3.3 正则脱敏
正则脱敏使用时,除了原始字符串之外,还需要提供正则表达式,以及占位替换表达式,以便处理数据。
使用示例:
// 获取正则脱敏处理器
RegexDesensitizationHandler desensitizationHandler =
DesensitizationHandlerHolder.getRegexDesensitizationHandler();
String origin = "[email protected]"; // 原始字符串
String regex = "(^.)[^@]*(@.*$)"; // 正则表达式
String replacement = "$1****$2"; // 占位替换表达式
String target = desensitizationHandler.handle(origin, regex, replacement); // 替换处理
System.out.println(target); // 结果:1****@qq.com
由于 BallCat 默认提供了 Email 类型的脱敏正则,所以可以使用以下代码来简化正则的定义:
// 使用内置的正则脱敏类型
String target2 = desensitizationHandler.handle(origin, RegexDesensitizationTypeEnum.EMAIL);
System.out.println(target2); // 结果:1****@qq.com
3.4 滑动脱敏
滑动脱敏则除了原始字符串之外,还需要提供左边和右边各自需要展示的明文数量,明文数量可以为 0。
使用示例:
// 获取滑动脱敏处理器
SlideDesensitizationHandler desensitizationHandler =
DesensitizationHandlerHolder.getSlideDesensitizationHandler();
String origin = "15805516789"; // 原始字符串
String target1 = desensitizationHandler.handle(origin, 3, 2); // 替换处理
System.out.println(target1); // 结果:158******89
和正则脱敏一样,由于 BallCat 默认提供了 PhoneNumber 类型的滑动规则,所以可以使用以下代码来简化:
// 使用内置的滑动脱敏规则
String target2 = desensitizationHandler.handle(origin, SlideDesensitizationTypeEnum.PHONE_NUMBER);
System.out.println(target2); // 结果:158******89
4. 脱敏注解
4.1 注解分类
在 web 服务中,服务端的响应数据很多情况下都是 json 数据,为了更方便的进行数据脱敏,BallCat 提供了以下三种脱敏注解。
目前 json 处理基于 Jackson,因为 springMvc 默认的 json 处理是使用 jackson
@JsonSimpleDesensitize
:简单类型脱敏@JsonRegexDesensitize
:正则类型脱敏@JsonSlideDesensitize
:滑动类型脱敏
4.2 定义 Json 序列化修改器
如果需要使用 json 注解脱敏,则需要将 BallCat 提供的 JsonSerializerModifier
注册到 Jackson 的 ObjectMapper
中。
示例如下:
//1.创建Object对象
ObjectMapper objectMapper = new ObjectMapper();
//2.实例化JsonSerializerModifier
JsonSerializerModifier modifier = new JsonSerializerModifier();
//3.将自定义序列化构建器 注册进ObjectMapper
objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(modifier));
如果是 spring-boot 项目,推荐使用以下方式进行 JSON 脱敏序列化修改器的注册:
/**
* 注册 Jackson 的脱敏模块
* @return JsonDesensitizeModule
*/
@Bean
public JsonDesensitizeModule jsonDesensitizeModule() {
JsonDesensitizeSerializerModifier desensitizeModifier = new JsonDesensitizeSerializerModifier();
return new JsonDesensitizeModule(desensitizeModifier);
}
4.3 注解添加
在需要进行脱敏处理的实体属性上添加对应的脱敏注解:
@Data
@Accessors(chain = true)
public class DesensitizationUser {
/**
* 用户名,不脱敏
*/
private String username;
/**
* 密码脱敏
*/
@JsonRegexDesensitize(type = RegexDesensitizationTypeEnum.ENCRYPTED_PASSWORD)
private String password;
/**
* 邮件
*/
@JsonRegexDesensitize(type = RegexDesensitizationTypeEnum.EMAIL)
private String email;
/**
* 手机号
*/
@JsonSlideDesensitize(type = SlideDesensitizationTypeEnum.PHONE_NUMBER)
private String phoneNumber;
/**
* 测试自定义脱敏
*/
@JsonSimpleDesensitize(handler = TestDesensitizationHandler.class)
private String testField;
}
4.4 JSON 脱敏
在 SpringMvc(Spring-Boot) 项目中,在 ObjectMapper 中完成了注册并在实体字段上添加了对应注解,就已经完成了脱敏处理。
当响应的 Json 数据类型为该 实体时,即会自动进行脱敏处理。
注意,这里需要保证 SpringMvc 中使用的 ObjectMapper 注册了脱敏处理器
如果需要手动处理数据,则可以使用依赖注入获取到对应 ObjectMapper:
@Autowired
private ObjectMapper objectMapper;
void test(){
DesensitizationUser user = new DesensitizationUser()
.setEmail("[email protected]")
.setUsername("xiaoming")
.setPassword("admina123456")
.setPhoneNumber("15800000000")
.setTestField("这是测试属性");
String value = objectMapper.writeValueAsString(user);
Assert.isTrue("{\"username\":\"xiaoming\",\"password\":\"adm****56\",\"email\":\"c****@foxmail.com\",\"phoneNumber\":\"158******00\",\"testField\":\"TEST-这是测试属性\"}"
.equals(value));
}
5. 扩展使用
5.1 自定义简单类型脱敏处理器
a) 首先定义自己的 SimpleDesensitizationHandler
实现类:
public class SimpleDesensitizatioHanderSPIExample implements SimpleDesensitizationHandler {
@Override
public String handle(String s) {
return "------";
}
}
b) BallCat 会利用 java 的 SPI 机制来加载简单脱敏处理器
所以只需在项目的 resources/META-INF/services
目录下新建名为
com.hccake.ballcat.common.desensitize.handler.SimpleDesensitizationHandler
的文件。
文件内容为自定义的脱敏处理器的全类名,多个实现则每个实现类名单独一行。
c) 使用示例
获取自定义处理器,入参为该处理器类目
// 获取简单脱敏处理器
SimpleDesensitizationHandler desensitizationHandler =
DesensitizationHandlerHolder.getSimpleHandler(SimpleDesensitizatioHanderSPIExample.class);
配合 JSON 注解使用时,只需指定 Handler 类型为该类即可
/**
* 测试自定义脱敏
*/
@JsonSimpleDesensitize(handler = SimpleDesensitizatioHanderSPIExample.class)
private String testField;
5.2 JSON 处理时,根据某些逻辑判断是否需要脱敏
需要用户进行脱敏策略接口的实现:
public interface DesensitizeStrategy {
/**
* 判断是否忽略字段
* @param fieldName {@code 当前字段名称}
* @return @{code true 忽略 |false 不忽略}
*/
boolean ignoreField(String fieldName);
}
在注册脱敏修改器的时候,进行
// 自定义策略,当前用户是管理员时忽略 phoneNumber 字段的脱敏处理
DesensitizeStrategy strategy = (fieldName) -> {
return fieldName.equals("phoneNumber") && isAdmin;
};
JsonSerializerModifier modifier = new JsonSerializerModifier(strategy);
5.3 自定义 JSON 脱敏注解示例
5.3.1 新增自定义注解
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomerDesensitize {
/**
* 类型字段
* @return type
*/
String type();
}
5.3.2 注册自定义脱敏类型处理器
//实现自定义脱敏处理器
CustomDesensitisedHandler customDesensitisedHandler = new CustomDesensitisedHandler();
//将自定义脱敏处理器绑定
DesensitizationHandlerHolder.addHandler(CustomDesensitisedHandler.class, customDesensitisedHandler);
5.3.3 注册注解处理器
//注册注解 处理器
AnnotationHandlerHolder.addHandleFunction(CustomerDesensitize.class, (annotation, value) -> {
CustomerDesensitize customerDesensitize= (CustomerDesensitize) annotation;
String type = customerDesensitize.type();
log.info("注解上的参数{}",type);
CustomDesensitisedHandler handler = (CustomDesensitisedHandler) DesensitizationHandlerHolder.getHandler(CustomDesensitisedHandler.class);
return handler.handle(value);
});
5.3.4 在实体字段上指定自定义注解
@CustomerDesensitize(type = "自定义注解")
private String customDesensitize;