1.背景
我所在的公司最近要求需要在所有地方都要脱敏敏感数据,应该是受faceBook数据泄密影响吧。
说到脱敏一般来说在数据输出的地方需要脱敏而我们数据落地输出的地方一般是有三个地方:
- 接口返回值脱敏
- 日志脱敏
- 数据库脱敏
这里主要说一下如何进行日志脱敏,对于代码中来说日志打印敏感数据有两种:
- 敏感数据在方法参数中
LOGGER.info("person mobile:{}", mobile);
对于这种建议写个Util直接进行脱敏,因为mobile这个参数名在代码中是无法获取的,当时有想过对传的参数使用正则匹配,这样的话效率太低,会让每个日志方法都进行正则匹配,效率极低,并且如果刚好有个符合手机号的字符串但是不是敏感信息,这样也被脱敏了。
LOGGER.info("person mobile:{}", DesensitizationUtil.mobileDesensitiza(mobile));
2.敏感数据在参数对象中
Person person = new Person();
person.setMobile(mobile);
LOGGER.info("person :{}", person);
对于我们业务中最多的其实就是上面的日志了,为了把整个参数打全,第一种方法需要把参数取出来,第二种只需要传一个参数即可,然后通过toString打印出这个日志,对于这种脱敏有两个方案
- 修改toString这个方法,对于修改toString方法又有三个办法:
- 直接在toString中修改代码,这种方法很麻烦,效率低,需要修改每一个要脱敏的类,或者写个idea插件自动修改toString(),这样不好的地方在于所有编译器都需要开个插件,不够通用。
- 在编译时期修改抽象语法树修改toString()方法,就像类似Lombok一样,这个之前调研过,开发难度较大,可能后会更新如何去写。
- 在加载的时候通过实现Instrumentation接口 + asm库,修改class文件的字节码,但是有个比较麻烦的地方在于需要给jvm加上启动参数 -javaagent:agent_jar_path,这个已经实现了,但是实现后发现的确不够通用。
- 可以看到上面修改上面toString()方法三个都比较麻烦,我们可以换个思路,不利用toString()生成日志信息,下面的部分具体解释如何去做。
2.方案
首先我们要知道当我们使用LOGGER.info的时候到底是发生了什么?如下图所示,我这里列举的是异步的情况(我们项目中都是使用异步,同步效率太低了)。
log4j提供给我们扩展的地方实在是太多了,只要你有需求都可以在里面自定义,比如美团点评自己的xmdt统一日志和线下报警日志都是自己实现的Appender,统一日志也对LogEvent进行了封装。
我们同样也可以利用Log4j2提供给我们的扩展性,在里面定制化自己的需求。