作者:白云鹏 职位:后端工程师
前言
最近在探索数据合规安全问题,想对所有java微服务中出现的敏感信息日志脱敏,但始终有一些顾虑。
大胆想象一下,JAVA微服务数量如果超过上百个,通过编码的方式,对每个微服务调整logback的相关配置,是一个非常庞大的工程,而且要对上百个微服务做上线操作,不知道你是否会感到畏惧!
以此为背景,深深陷入思考之中,有没有更快捷,更安全可靠的方式来实现呢?
突发奇想,如果用JavaAgent来实现,是不是可以满足一切幻想呢?而且大名鼎鼎的skywalking和pinpoint,也都是通过JavaAgent来实现全链路监控的。
有这么成功且优秀的案例作为参考,我今天就带大家一步一步来实现,利用JavaAgent技术对Java微服务进行日志脱敏,希望对大家有所帮助。
Java Agent 可以理解为字节码增强技术,通常结合字节码修改框架技术一起使用,今天的文章就以java Agent和ASM字节码操纵框架为例,探索一下字节码技术的魅力。
对于这两个名词相信大家也不会感到陌生,铺天盖地的技术文章随处可查,这里就不再赘述,直接进入实践阶段。
在JVM加载class二进制文件的时候,动态修改logback的class文件,在debug、info、warn、error等方法前,增加一些规则的配置,对原消息进行包装处理,将脱敏后的日志信息打印输出。
3.1 需要搭建一个Agent maven服务(^_^取名log-desensitization-agent)。
需要添加maven依赖,asm是核心依赖,其他两个可以根据需求自行添加。
增加maven打包插件
3.2 新建一个Agent入口类(LogDesensitizationAgent.java)
当Java 虚拟机启动时,执行 main 函数之前,JVM 会先运行-javaagent所指定 jar 包内 Premain-Class 这个类的 premain 方法。
desensitizationRuleService.initDesensitizationRules() 是自定义的方法,获取相关配置信息,脱敏的时候,根据这个配置进行处理。直接上图,具体大家可以根据需求或喜好做相关的配置获取。 本文选取最简单的环境变量方式^_^
(展示一下,可以从http、变量或配置文件等多种方式获取脱敏配置)
实现transform方法,对目标类进行处理。
ch/qos/logback/classic/Logger是我们需要转换的logback类,该类的源码中包含了所有的debug、info、warn、error等方法的重载,也是我们的修改目标方法。
源码摘要(简单展示一下,详细的源码请自行查阅^_^)
修改字节码
ASM中最核心的三个重要类
ClassReader:字节码的读取与分析引擎,提供accept方法,入参是ClassVisitor,按照一定的顺序来调用ClassVisitor当中的visitXxxx()方法。
ClassWriter:ClassVisitor的子类,用于生成二进制,重写.class文件。
ClassVisitor:是一个抽象类,自定义ClassVisitor重写visitXxxx()方法,可捕获ASM类结构访问的所有事件。
响应处理流程:Target.class --> ClassReader --> ClassVisitor --> ClassWriter --> Target.class文件
3.3 自定义ClassVisitor(LogDesensitizationClassVisitor.java),访问目标方法
加载info、debug、warn、error方法中第一个出现的字符串变量的引用,调用静态方法LogDesensitizationClassVisitor.desensitizeLogMessage(String logMessage),并把变量传入,对字符串变量进行处理,再存储回字符串变量值。
此方法根据读取到的配置,将字符串中,符合正则规则的部分全部替换成***或者xxx***xxx的形式,可以自己根据业务需求自行编写实现方法,过于简单就不发出来了。
至此,Java Agent代码核心部分已经全部粘贴出来了。完成所有代码部分,可以通过maven package将agent jar包打到本地,位置在target文件夹下。
3.4 为微服务构建一个带有agent的基础镜像。
编写Dockerfile文件编写启动脚本entrypoint.sh文件
目录结构大致是这样的,执行docker-compose构建命令,推送到自己的仓库中。
3.5 微服务修改部分非常简单,只需要修改Dockerfile文件的基础镜像,然后运行进行编译后构造镜像。
3.6 启动时增加运行时的环境变量,根据你代码编写规则的变量。
这样,就实现了通过JavaAgent的方式实现了日志脱敏,对微服务代码没有入侵,上线更安全,使用也很简单。你学会了吗?
4、总结
用非常简单的代码实现了非侵入性的日志脱敏,对微服务本身的业务代码没有任何侵害,不需要了解和学习logback语法配置,只需要你会正则,即可实现脱敏。
这是一个抛砖引玉的案例,实际上Java Agent + ASM可以实现更多更有用有的功能。