应对 Log4j 严重漏洞
目录
简介
在流行的 Apache Log4j 日志记录库中发现了一个严重的远程代码执行 (RCE) 漏洞,影响版本 2.0 直到并包括 2.14.1。此漏洞已影响大量基于 JVM 的系统。有关漏洞本身的更多信息,请参阅 CVE-2021-44228。
更新(2021 年 12 月 22 日):自第一篇文章发布以来,又发现了两个其他漏洞 - CVE-2021-45046 和 CVE-2021-45105 - 因此请务必查看不同部分以获取更新的说明。
此漏洞正在被积极利用。所有 Gradle 用户都应评估其软件项目是否容易受到攻击,如有必要,尽快更新到 Log4j 2.17.0 或更高版本。我们已在下方提供了有关如何识别和预防项目中此漏洞的说明。
我们强烈建议您配置 Gradle 构建,以使用依赖约束拒绝任何有漏洞的 Log4j 版本。
除了项目依赖项之外,我们还建议保护您的构建依赖项,如下所述。
请注意,Gradle 构建工具本身不受此漏洞的影响,因为它不使用 Log4j。Gradle 使用 SLF4J 和自定义日志记录实现,不易受到有漏洞的字符串替换的影响。
Gradle Scala 插件使用 Zinc Scala 编译器,该编译器依赖于有漏洞的 Log4j 版本。但是,在这种情况下,Gradle 也提供了自己的日志记录实现,默认情况下不使用 Log4j。
此帖子的更新
保护您的项目依赖 #
1. 确定您的项目是否使用了有漏洞的 Log4j 版本 #
首先,使用依赖项报告或 Build Scan™ 验证您的项目是否使用了有漏洞的 Log4j 版本。有关详细信息,请参阅查看和调试依赖项。
版本介于 2.0 和 2.16.0(包括两者)之间的所有 org.apache.logging.log4j:log4j-core
版本都容易受到攻击。
2. 将 Log4j 依赖升级到非漏洞版本 #
在每个子项目的构建脚本或版本目录的 dependencies
块中升级 Log4j 依赖项,如果您使用依赖项的集中声明。
更新(2021 年 12 月 14 日):Log4j 发布了 2.16.0,它禁用并删除了漏洞核心功能的支持。在某些非默认配置中,软件 使用 2.15.0 时仍然可能存在漏洞。为了绝对确定,您应该更新到 2.16.0。以下说明已修改为使用 2.16.0。
更新(2021 年 12 月 22 日):Log4j 发布了 2.17.0,它修复了另一个漏洞。为了绝对确定,您应该更新到 2.17.0。以下说明已修改为使用 2.17.0。
3. 防止意外解析项目中有漏洞的 Log4j 版本 #
鉴于此漏洞的严重性,我们建议采取以下额外步骤,以防止意外包含有漏洞的版本。请注意,即使您没有直接使用 Log4j,也有可能通过您的某个依赖项传递性地解析出有漏洞的版本。
使用依赖项约束功能,以确保您的项目无法解析受影响的 Log4j 版本,方法是将以下代码段添加到您的 Gradle 构建中
dependencies {
constraints {
implementation("org.apache.logging.log4j:log4j-core") {
version {
strictly("[2.17, 3[")
prefer("2.17.0")
}
because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities")
}
}
}
除非 log4j-core 出现在依赖项图中,否则约束将不会被激活。约束将强制将依赖项升级到至少 2.17.0,或者在无法满足严格版本约束时使构建失败。
请注意,在此处使用 implementation
配置将涵盖 Java 库或应用程序的默认设置。但是,如果您有自定义配置或更高级的设置,您还应该将此约束添加到其他配置中。
此外,如果您使用Gradle 模块元数据发布带有此类约束的库,则如果任何使用您的库的构建尝试解析有漏洞的 log4j-core 版本,也会导致它们失败。
4. 防止在组织范围内使用有漏洞的 Log4j 版本 #
您的组织可能会利用应用于所有项目的共享插件。在这种情况下,您还可以将上述约束应用于组织中的所有项目。
如果您使用预编译脚本插件,只需将上面的代码段复制到应用于所有 JVM 项目的脚本中。如果您使用二进制插件,则以下是与 DSL 代码段等效的 Java 代码
project.getDependencies().constraints(constraints -> {
constraints.add("implementation", "org.apache.logging.log4j:log4j-core", c -> {
c.version(v -> {
v.strictly("[2.17, 3[");
v.prefer("2.17.0");
});
c.because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities");
});
});
保护您的构建依赖 #
更新(2021 年 12 月 15 日):您无需将其应用于 Gradle 7.3.2 及更高版本。Gradle 自动要求 Log4J 版本为 2.16.0 或更高版本。
更新(2021 年 12 月 22 日):您无需将其应用于 Gradle 7.3.3 及更高版本。Gradle 自动要求 Log4J 版本为 2.17.0 或更高版本。对于仍在使用 6.x 系列的用户,Gradle 6.9.2 也执行此操作。
除了项目依赖项之外,您的项目可能还使用内部或第三方 Gradle 插件。这些插件也有自己的依赖项,可能会意外地将有漏洞的 Log4j 依赖项引入到构建类路径中。
换句话说,您的构建逻辑可能与您的生产代码以相同的方式容易受到攻击。虽然此类漏洞可能更难利用,但您也可以使用以下代码段保护您的构建依赖项
buildscript {
dependencies {
constraints {
classpath("org.apache.logging.log4j:log4j-core") {
version {
strictly("[2.17, 3[")
prefer("2.17.0")
}
because("CVE-2021-44228, CVE-2021-45046, CVE-2021-45105: Log4j vulnerable to remote code execution and other critical security vulnerabilities")
}
}
}
}
该代码段应应用于每个构建脚本中的 buildscript
块以及 settings.gradle(.kts) 文件,并确保只有 Log4j 2.17.0 及更高版本可以解析为构建依赖项。该语句必须位于文件的顶部。
保护插件门户用户 #
鉴于最初 Log4j 漏洞的严重性,Gradle 团队希望改善插件门户用户的状况。我们正在采取措施,以确保没有新的插件可以依赖有漏洞的 Log4j 版本。以下更改已可用,将在以后的更新中强制执行。
作为 Gradle 插件作者,您可能直接或间接地依赖于有漏洞的 Log4j 版本。为了保护您的插件用户,Gradle 已在其 plugin-publish
插件中添加了新的验证规则。
我们已发布 Plugin Publish Plugin 的 0.19.0 版本,该版本会自动检测有漏洞的 Log4j 插件依赖项,如果发现任何依赖项,则会通过使构建失败来阻止插件发布。没有自动升级,因为通常 Gradle 插件不需要 Log4j,因为 Gradle 运行时不使用此库进行日志记录。修复问题(删除依赖项或升级它)是插件作者的工作。
在不久的将来,使用此版本的 Plugin Publish Plugin 将成为强制性的,插件门户将拒绝使用旧版本插件完成的任何发布。
Gradle Enterprise 产品 #
一些 Gradle Enterprise 产品受到了 Log4j 漏洞的影响。
Gradle Enterprise、Test Distribution Agent 和 Build Cache Node 的新版本于 2021 年 12 月 13 日发布。
更新(2021 年 12 月 22 日):Gradle Enterprise 2021.4 将 Log4j 升级到 2.17.0
反馈 #
如果您对我们的论坛或 Gradle 社区 Slack 有任何疑问,请告知我们。