在流行的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 Module Metadata定义的这种约束来发布你的库,它也会导致任何消耗你的库的构建失败,如果他们试图解决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或更高。Gradle 6.9.2也为仍在6.x线上的用户做了这个。
除了项目的依赖性外,你的项目可能还使用了内部或第三方的Gradle插件。这些插件也有它们自己的依赖关系,可能会意外地将有漏洞的Log4j依赖关系带到构建classpath中。
换句话说,你的构建逻辑可能与你的生产代码一样存在漏洞。虽然这种漏洞可能更难被利用,但你也可以用下面的代码段来保护你的构建依赖。
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及以上版本可作为构建依赖项被解决。 该声明必须在文件的顶部。
保护Plugin Portal用户
鉴于最初Log4j漏洞的严重性,Gradle团队希望为Plugin Portal的用户改善情况。 我们正在采取措施,确保没有新的插件可以依赖有漏洞的Log4j版本。 以下变化已经可以使用,并将在以后的更新中强制使用。
作为Gradle插件的作者,你有可能直接或横向依赖有漏洞的Log4j版本。 为了保护你的插件用户,Gradle已经在其plugin-publish 插件中添加了新的验证规则。
我们已经发布了0.19.0版本的插件发布插件,它可以自动检测有漏洞的Log4j插件的依赖关系,如果发现任何依赖关系,就会通过失败的构建来阻止插件的发布。 没有自动升级,因为通常Gradle插件不需要Log4j,因为Gradle运行时不使用这个库做日志。 插件作者的工作是通过移除依赖关系或升级它来解决问题。
在不久的将来,使用这个版本的Plugin Publish Plugin将成为强制性的,即让Plugin Portal拒绝任何用旧版本的插件完成的发布。
Gradle企业版产品
一些Gradle Enterprise产品受到了Log4j漏洞的影响。
2021年12月13日,Gradle Enterprise、测试分发代理和构建缓存节点的新版本发布。
更新(2021年12月22日)。Gradle Enterprise 2021.4将Log4j升级到2.17.0
反馈信息
如果您有任何问题,请在我们的论坛或Gradle社区Slack上告诉我们。