使用fastjson进行序列化时进行数据脱敏
fastjson 是阿里巴巴开源的一款优秀的java生态下序列化/反序列化产品,我们可以在不同的服务之间进行数据交互时使用它,同样可以输出日志时使用fasnjson把对象转化为String, 然后再进行采集,比调用对象的toString方法靠谱,比如如果对象内部没有实现toString方法就不能正确输出想要的信息, 另一方面json格式的日志数据,后续可观性也会好一些;问题使用fastjso...
fastjson 是阿里巴巴开源的一款优秀的java生态下序列化/反序列化产品,我们可以在不同的服务之间进行数据交互时使用它,同样可以输出日志时使用fasnjson把对象转化为String, 然后再进行采集,比调用对象的toString方法靠谱,比如如果对象内部没有实现toString方法就不能正确输出想要的信息, 另一方面json格式的日志数据,后续可观性也会好一些;
问题
使用fastjson序列化对象输出日志, 引出了另一个问题,由于我司是做支付业务的,对于用户的一些敏感信息(姓名, 身份证号, 手机号, 银行卡号, 卡有效期等)是绝对不能直接原文输出的,因此对于这部分数据就要进行脱敏处理;
分析
现状我们项目代码中是各自独立处理每个字段,自定义加工进行脱敏,这种方式要求每个使用的地方重复处理,工作量大同时不能保证脱敏规则统一,也容易出错;首先脱敏这件事情是一个共有的需求,各个程序中会有很多地方都有这样的需要,因此我们解决这个事情最好是有一个通用的办法;使用fastjson进行对象到字符串的转化是一个统一处理点,可以实现脱敏统一处理,从此切入试下
调研
查看了fastjson官方的文档,发现其中提供filter机制,可以在序列化过程中加入自定义的拦截处理,对json数据中的key-value加工处理;那我们就可以创建自定义的脱敏处理filter实现我们需要的功能嘛
实施
自定义filter进行脱敏处理,那在filter的逻辑中,我们要知道对象的哪些字段需要以什么规则进行脱敏呢?
可以通过给脱敏对象属性添加自定义注解,然后注解属性上再指定定义脱敏规则枚举,最后在filter中检测注解进而进行脱敏处理;
- 脱敏注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 需要脱敏的对象
* @author Hinsteny
* @version $ID: Desensitization 2018-12-12 20:12 All rights reserved.$
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitization {
/**
* 脱敏规则类型
* @return
*/
DesensitionType type();
/**
* 附加值, 自定义正则表达式等
* @return
*/
String[] attach() default "";
}
- 脱敏规则枚举
/**
* @author Hinsteny
* @version $ID: DesensitionType 2018-12-12 20:40 All rights reserved.$
*/
public enum DesensitionType {
PHONE("phone", "11位手机号", "^(\\d{3})\\d{4}(\\d{4})$", "$1****$2"),
IDENTITYNO("identityNo", "16或者18身份证号", "^(\\d{4})\\d{8,10}(\\d{4})$", "$1****$2"),
BANKCARDNO("bankCardNo", "银行卡号", "^(\\d{4})\\d*(\\d{4})$", "$1****$2"),
CUSTOM("custom", "自定义正则处理", ""),
TRUNCATE("truncate", "字符串截取处理", ""),
;
String type;
String describe;
String[] regular;
DesensitionType(String type, String describe, String... regular) {
this.type = type;
this.describe = describe;
this.regular = regular;
}
public String getType() {
return type;
}
public String getDescribe() {
return describe;
}
public String[] getRegular() {
return regular;
}
}
- 自定义脱敏处理filter
import com.alibaba.fastjson.serializer.ValueFilter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 在fastjson中使用此过滤器进行脱敏操作
* @author Hinsteny
* @version $ID: ValueDesensitzeiFilter 2018-12-12 10:06 All rights reserved.$
*/
public class ValueDesensitizeFilter implements ValueFilter {
private Logger logger = LoggerFactory.getLogger(ValueDesensitizeFilter.class);
@Override
public Object process(Object object, String name, Object value) {
if (null == value || !(value instanceof String) || ((String) value).length() == 0) {
return value;
}
try {
Field field = object.getClass().getDeclaredField(name);
Desensitization desensitization;
if (String.class != field.getType() || (desensitization = field.getAnnotation(Desensitization.class)) == null) {
return value;
}
List<String> regular;
DesensitionType type = desensitization.type();
switch (type) {
case CUSTOM:
regular = Arrays.asList(desensitization.attach());
break;
case TRUNCATE:
regular = truncateRender(desensitization.attach());
break;
default:
regular = Arrays.asList(type.getRegular());
}
if (regular.size() > 1) {
String match = regular.get(0);
String result = regular.get(1);
if (null != match && result != null && match.length() > 0) {
return ((String) value).replaceAll(match, result);
}
}
} catch (NoSuchFieldException e) {
logger.warn("ValueDesensitizeFilter the class {} has no field {}", object.getClass(), name);
}
return value;
}
private List<String> truncateRender(String[] attachs) {
List<String> regular = new ArrayList<>();
if (null != attachs && attachs.length >1) {
String rule = attachs[0];
String size = attachs[1];
String template, result;
if ("0".equals(rule)) {
template = "^(\\S{%s})(\\S+)$";
result = "$1";
} else if ("1".equals(rule)) {
template = "^(\\S+)(\\S{%s})$";
result = "$2";
} else {
return regular;
}
try {
if (Integer.parseInt(size) > 0) {
regular.add(0, String.format(template, size));
regular.add(1, result);
}
} catch (Exception e) {
logger.warn("ValueDesensitizeFilter truncateRender size {} exception", size);
}
}
return regular;
}
}
更多推荐
所有评论(0)