本文目录导读:

Log4Shell(CVE-2021-44228)是2021年底爆发的、影响极其广泛的严重漏洞,修复它不仅仅是打一个补丁,而是一个涉及应急响应、版本升级、纵深防御的系统性过程。
以下是一个典型的、从“踩坑”到“成功”的完整修复案例复盘。
案例背景
某大型电商平台(假设名为“云购商城”)在2021年12月10日监控到安全公告后,经扫描发现其用户行为分析服务(UBA)和订单日志聚合服务使用了Apache Log4j 2.x(版本为2.14.1),确认存在严重漏洞,攻击者可利用该漏洞实现远程代码执行(RCE)。
面临的挑战:
- 影响面广:两个核心服务依赖 Log4j,且存在大量历史版本库。
- 业务连续性:订单日志服务高峰期QPS极高,不能停服太久。
- 依赖复杂性:部分第三方组件(如ES客户端)捆绑了Log4j,不能直接替换版本。
修复阶段一:紧急止血(黄金半小时)
目标: 在最短时间内阻断攻击路径,防止被利用。
-
临时缓解措施(立即执行,不停服):
- 修改JVM参数:在应用启动命令中添加
-Dlog4j2.formatMsgNoLookups=true,强制关闭 lookup 功能。 - 修改配置文件:在
log4j2.component.properties中添加log4j2.formatMsgNoLookups=true。 - 环境变量:设置
LOG4J_FORMAT_MSG_NO_LOOKUPS=true。 - 注意:这一步针对 2.10 以下的版本无效,且容易遗漏节点。
- 修改JVM参数:在应用启动命令中添加
-
网络层拦截(WAF策略):
- 在云防火墙/WAF上紧急添加了针对
${jndi:ldap://...}、${jndi:rmi://...}等关键词的拦截规则,将攻击特征字符拦截在应用之外。
- 在云防火墙/WAF上紧急添加了针对
-
结果:在 30分钟内,成功阻断了针对该服务的已知攻击路径,业务未中断。
修复阶段二:根治升级(核心动作)
目标: 彻底移除漏洞代码,消除风险。
排查与升级策略(重点):
-
步骤1:全量盘点依赖。
- 使用
mvn dependency:tree或gradle dependencies定位所有 Log4j 版本。 - 发现除了显式依赖(2.14.1),还有 传递依赖(如
elasticsearch7.x 自带 Log4j 2.11.1),无法直接改版本。
- 使用
-
步骤2:制定升级路线(非一刀切)。
- 对于 显式依赖 的模块:直接升级到 Log4j 2.17.0(或更高版本,这是官方推荐的修复版本)。
- 对于 传递依赖 且无法升级的模块:在
pom.xml或build.gradle中使用 排除依赖(exclusion) 和 强制版本(force),将 Log4j 统一升级到 2.17.0。 - 关键点:升级时务必同时升级 log4j-core 和 log4j-api,防止版本不一致。
-
步骤3:灰度发布,验证核心功能。
- 首先在预发布环境(Staging)部署升级后的包。
- 重点验证日志输出格式和吞吐量,Log4j 2.17.0 对性能有所优化,但需确保无回归。
- 检查是否存在因为使用了
Message Lookup功能(如${ctx:userId})而导致的日志格式异常,若有,需改为PatternLayout中的%X参数。
-
步骤4:全量替换。
- 采用滚动发布(Rolling Update)策略,逐步替换生产环境所有节点,确保集群无单点故障。
修复阶段三:加固与复盘(纵深防御)
目标: 防止绕过补丁的新变种,并提升整体安全水位。
-
设置 Log4j 安全属性:
- JDK 版本升级:将所有 JDK 升级到 8u191 及以上,限制远程加载的信任码库(限制 LDAP 远程对象)。
- 配置
log4j2.enableJndi=false(在 2.16.0+ 中默认禁用 JNDI,在 2.17.0 中是彻底移除)。
-
运行时自保护(RASP):
- 在主机安全Agent(如云安全中心)上开启 RASP 防护,即便后续出现绕过的 Payload,也能在Java虚拟机层面阻断
exec()系统调用。
- 在主机安全Agent(如云安全中心)上开启 RASP 防护,即便后续出现绕过的 Payload,也能在Java虚拟机层面阻断
-
自动化扫描与准入:
- 将 Log4j 版本扫描接入 CI/CD 流水线,在构建阶段若扫描到低版本 Log4j 则直接 阻断构建,防止漏洞二次引入。
-
复盘与文档化:
- 复盘发现,工单系统的“标题”字段允许用户输入,且存在反射日志记录,这是最容易被攻击的点,修复后对输入框增加了严格的白名单校验。
修复结果与关键数据(案例演示)
- 漏洞发现:监控公告后 2小时 内确认影响面。
- 阻断时间:确认漏洞后 30分钟 内完成全球WAF规则拦截。
- 修复完成: 72小时 内完成全部核心链路服务升级至 2.17.0。
- 安全验证:升级后,由安全团队使用
dnslog和Ceye.io进行了模拟攻击测试(如${jndi:ldap://x.dnslog.cn}),确认无法解析,漏洞成功修复。
核心经验总结(应对Log4Shell的关键)
-
不是版本越高越好,但要避开漏洞区间:
- 安全版本:Log4j 2.17.0(Java 8+)、2.12.4(Java 7+)、2.3.2(Java 6+)。
- 禁止使用 2.15.0(存在新的 DoS 漏洞 CVE-2021-45046)。
-
“排除法”比“替换法”更常用:
绝大多数应用都因为依赖 Elasticsearch 等框架捆绑了 Log4j,直接改版本常会导致冲突,使用 Maven Enforcer 插件强制指定版本号是更稳妥的做法。
-
默认拒绝 JNDI:
- 请务必在配置文件或 JVM 参数中显式设置
log4j2.enableJndi=false(适用于 2.16.0 以下)或移除该属性(2.17.0),这是最根本的阻断。
- 请务必在配置文件或 JVM 参数中显式设置
如果你目前仍在排查代码,建议优先检查 pom.xml 或 package-lock.json,确认最终生效的版本是 2.17.0 及以上,而不是仅看声明版本。