日志敏感数据脱敏

应该每个公司都会有要求吧?日志不能打印用户的敏感信息,如身份证号,密码,银行卡号等。刚好最近在整理有关接口的事项,就顺便研究了下日志脱敏的几种实现。

一 日志配置文件设置pattern规则

这种呢,就是直接修改你的日志配置文件,比如你的是log4j2.xml,你可以这样写:

            
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%traceId] [%t] %-5level %logger{1.} - %msg%n
                    
            

上面这个就可以过滤掉类似 "IdNo":"12345678901234567X",这样的字符。但是这个是原生的Pattern,只能写一个replace规则,比如有多个关键字需要匹配,如还想匹配mobile,需要制定不同的替换规则,这个我是没找到直接修改文件就可以实现的方法的。

二 自定义Pattern,实现多种替换规则

这种方法就可以弥补上面方法的不足,可以写多个关键字匹配替换规则,实现多种源信息的脱敏。
参考文档: https://blog.csdn.net/vcstrong/article/details/80527455
又已log4j2为例,实现的思路就是:
自己实现类,继承自org.apache.logging.log4j.core.layout.AbstractStringLayout,在方法

@Override
    public String toSerializable(final LogEvent event) {
        final StringBuilder buf = new StringBuilder();
        for (final PatternFormatter formatter : formatters) {
            formatter.format(event, buf);
        }
        String str = buf.toString();
        if (replace != null) {
            str = replace.format(str);
        }
        return str;
    }

中实现自定义的脱敏规则。其中replace也是自定义的,从日志配置文件中中读取到匹配替换规则。

 @PluginFactory
    public static CustomRegexReplaces createRegexReplacement(
            @PluginElement("replaces") final RegexReplacement[] replaces) {
        if (replaces == null) {
            log.info("no replaces is defined");
            return null;
        }
        return new CustomRegexReplaces(replaces);
    }

最后就可以根据自己的需求添加replace规则。

           
                %d{yyyy-MM-dd HH:mm:ss.SSS} [%traceId] [%t] %-5level %logger{1.} - %msg%n
                
                    
                    
                
            

三 自定义序列化规则

现在常用的数据格式是json,我一般用到的工具类是gson,所以可以考虑自己修改下gson的序列化方法,实现数据的脱敏。一开始的想实现的就是,我有一个类,有些属性加上了注解,比如标注它为身份证号,需要是用身份证号的脱敏方式,那么在用gson的转为json字符串方法时,这个注解被读到,并按照身份证脱敏的方式输出字符串。如下:

@DesensitizationType
public class User {
    //自定义的脱敏注解,代表脱敏类型为password
    @Desensitization(type = DesenseType.PASSWORD)
    String password;
    //自定义的脱敏注解,标注的其他脱敏方式的类和方法
    @Desensitization(method = "trueName", className = "com.c4tman.play.logPrint.desense.MyDesensitization")
    String name;

    @Desensitization(type = DesenseType.MOBILE)
    String mobile;

    @Desensitization(type = DesenseType.ID_CARD)
    String idCard;

    @Desensitization(type = DesenseType.VERIFY_CODE)
    String verifyCode;
  .......

当将user实例json化,就会按照标注的脱敏规则去自行脱敏数据。
接下来就是要改造gson的序列化方法了,核心思想就是

private static Gson GSON = new GsonBuilder().registerTypeAdapterFactory(new MyTypeAdapterFactory()).create();

其中MyTypeAdapterFactory是自己的实现,代码如下:

public class MyTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public  TypeAdapter create(Gson gson, TypeToken typeToken) {
        Class rawType = (Class) typeToken.getRawType();
        //如果这个类被@DesensitizationType标记,那么按自定义脱敏规则执行
        boolean b = rawType.isAnnotationPresent(DesensitizationType.class);
        if (b) {
            return new MyTypeAdapter();
        }
        return null;
    }
}

其中最重要的就是MyTypeAdapter了,方法

 public void write(JsonWriter jsonWriter, Object o) {}

就是序列化的规则,需要自己改写。我的思路就是获取object的每个属性,判断是否被@Desensitization标记,如果标记了,就按照标记的规则去输出。
其中涉及到大量的反射,我的反射是真的学的渣/(ㄒoㄒ)/~~所以写的感觉就是坑坑洼洼,一点都不优雅,而且还有好多中数据类型打印不出来。比如Map,我无法通过传入一个Object,去判断为Map时,它的key,value的类型,进而进行脱敏。哎,反正就是功能实现的不全面,只能当作是一个练习反射的例子了。
所有的源码地址:https://github.com/C4TMAN/maskdata.git
写的很烂,bug多,功能也不全,仅供参考。同时欢迎交流,希望大佬教我怎么把Map给脱敏了(●ˇ∀ˇ●)。

最后这个的实现效果就是
原版:

脱敏版:

= =mingtianxie

你可能感兴趣的:(日志敏感数据脱敏)