本项目为 log4j CVE-2021-44228 漏洞提供了一个通用变通方案,适用于短期内无法重建项目或修补 log4j-core jar 包的场景。
其背后的思路很简单:我们通过 Java 运行时参数 "-Xbootclasspath/a" 强制类加载器加载一个 "空版本" 的 JndiLookup 类。
因此,整个变通方案仅包含这一个类 "org.apache.logging.log4j.core.lookup.JndiLookup.java",并且没有其他依赖项。
为了方便通过 Maven 编译和打 jar 包,项目中还提供了一个 pom.xml,但你也可以直接使用你喜欢的 JDK,通过 "javac" 和 "jar" 命令完成同样的操作。
请注意,这个 "JndiLookup" 类的空版本与原始 log4j2 实现并不兼容,否则在某些类加载情况下会失败。
应用此变通方案时,你会看到以下消息:
"WARN JNDI lookup class is not available because this JRE does not support JNDI.
JNDI string lookups will not be available, continuing configuration.
Ignoring java.lang.ClassCastException: class org.apache.logging.log4j.core.lookup.JndiLookup"
Log4j2 仍会正常运行,只是不再使用任何 JNDI 查找——就这样,JNDI 查找已被禁用!
编译好类并创建 jar 文件后,只需在你的 Java 命令开头添加 "-Xbootclasspath/a:<你的变通方案 jar 文件路径>" 选项,并指向放置 jar 文件的目录(例如 log4j-workaround-1.0-SNAPSHOT.jar)。有关如何操作,请参见概念验证部分。
应用此变通方案的 Java 命令可以启动任何东西(Weblogic、Tomcat、Spring 构建的 fat jar 等)。
如果你只关心变通方案,而不关心验证它是否真的有效,可以忽略以下内容。
为了验证该方法,我添加了一个 "POC" 文件夹,其中包含另一个 Maven 项目。我并没有使用单元测试,而是更贴近实际生产环境,例如显式命令行启动 fat jar,或者像我验证过的 Tomcat 那样启动容器。
概念验证包含两个类:"POC.java" 用于在命令行测试变通方案,"POCServlet.java" 用于在应用服务器中进行相同测试。
两种场景都尝试记录 "${jndi:ldap://localhost/test}",如果不应用变通方案,log4j 会尝试连接本地主机的 ldap 并因连接被拒绝而失败。
要运行命令行 POC(在 Maven 中构建完成后):
进入 "target\log4j-workaround-1.0-SNAPSHOT\WEB-INF" 目录,然后运行(如果你在 Windows 命令行下):
java -Xbootclasspath/a:..\..\..\..\target\log4j-workaround-1.0-SNAPSHOT.jar -classpath classes;lib\* com.github.grimch.log4j_workaround.poc.POC
要在 Tomcat 中运行 POC:
为什么使用 "-Xbootclasspath" 而不是仅仅将变通方案 jar 作为 "常规" 类路径的第一个条目? 某些容器允许你影响类加载,使得部署的应用归档中的 jar 文件优先于系统类路径中的相同 jar。 而引导类路径中的内容则优先于所有其他内容。
不过,如果你确定不会出现类似情况(例如 Weblogic 中的 "prefer-application-packages"),那么也可以使用 "-classpath" 替代方案。