设置 LOG4J_FORMAT_MSG_NO_LOOKUPS=true 仅对 Log4j 2.10+ 有效,因旧版本不解析该变量;需在 Java 进程启动前通过服务脚本或 systemd Environment 注入,而非用户 shell 配置,并须验证是否生效。

直接在全局系统环境变量中设置 LOG4J_FORMAT_MSG_NO_LOOKUPS=true 可以临时禁用 Log4j2 的 lookup 功能,从而阻断 CVE-2021-44228 的核心攻击链。但这个操作是否生效,**完全取决于 Java 进程启动时能否读取到该变量,且 Log4j 版本必须 ≥ 2.10**。
为什么只对 2.10+ 有效?
Log4j 2.9.x 及更早版本压根不识别 LOG4J_FORMAT_MSG_NO_LOOKUPS 这个环境变量,代码里没写解析逻辑。强行设置等于白设——进程启动后查 System.getProperty("log4j2.formatMsgNoLookups") 或日志行为,照样触发 JNDI 查找。
- 2.10–2.14.1:支持该变量,设为
true后会跳过消息格式化阶段的 lookup 解析 - 2.15.0+:默认关闭 lookup,该变量已废弃(但仍兼容)
- 2.17.1+:彻底移除 JndiLookup 类,变量无实际作用
怎么设才真正生效?
不能只改 /etc/environment 或 ~/.bashrc 就完事。Java 进程必须在启动前就“看到”这个变量。常见可靠方式:
- 在服务启动脚本(如
/etc/init.d/xxx、/usr/lib/systemd/system/xxx.service)的Environment=或ExecStart前加env LOG4J_FORMAT_MSG_NO_LOOKUPS=true - 对于 systemd 服务,在
[Service]段写:Environment="LOG4J_FORMAT_MSG_NO_LOOKUPS=true",然后systemctl daemon-reload && systemctl restart xxx - 避免用
export LOG4J_FORMAT_MSG_NO_LOOKUPS=true放在用户 shell 配置里——除非你确定所有 Java 进程都由该用户 shell 派生(比如手动java -jar app.jar)
验证有没有被进程读到?
别信配置文件写了就完事。最简单验证法:
- 重启目标 Java 服务后,执行
ps aux | grep java,看启动命令行里是否出现-Dlog4j2.formatMsgNoLookups=true(JVM 参数优先级更高,若同时存在会覆盖环境变量) - 或进 JVM 进程,用
jcmd <pid> VM.system_properties | grep log4j2.formatMsgNoLookups确认值是否为true - 更直接:发一个
${jndi:ldap://xxx}日志 payload,观察 DNS 请求是否发出(用tcpdump -i any port 53抓包)
环境变量只是临时补丁,不是修复。它不改变 jar 包本身,也不防绕过(比如某些旧版本配合 ${${lower:j}ndi... 仍可能触发)。真正要稳,得升级到 2.17.1 或更高,或者确认应用根本没用 Log4j2 —— 很多号称“修复了”的系统,其实只是把变量设在了错误的位置,进程根本没加载。


















