在 Elasticsearch 中缓解 Log4j2/Log4Shell
2021年12月16日 | by mebius
原文:Mitigate Log4j2 / Log4Shell in Elasticsearch
注:本页面内容为本人截至2021-12-14 18:30 UTC的当前理解结果。
Log4j2 安全问题 (CVE-2021-44228),也称为 Log4Shell,影响版本 2.0-beta9 到 2.14.1 并在日志库的 2.15.0 中修复,很糟糕。远程代码执行 (RCE) 的漏洞得分为 10 分(满分 10 分)——利用它很简单。
全面评估应用程序的风险也很复杂,因为包含该库的易受攻击版本不足以使其可被利用,并且各种扫描应用会报告误报:
- JVM 选项 log4j2.formatMsgNoLookups=trutgcodee 可以缓解这个问题。你需要重启,这是修补后的 Log4j 2.15.0 版本中的默认行为。你希望此设置停止评估你的日志消息,这是对这种攻击的直接停止。但是,该选项仅适用于 ≥ 2.10 版本,不能用于早期版本。
- 根据这篇博文(从中文翻译过来),JDK 6u211、7u201、8u191 和 11.0.1 版本通过 com.sun.jndi.ldap.object.trustURLCodebase 抵御 LDAP 攻击向量。尽管还有其他示例 (1, 2, 3, 4) 展示com.sun.jndi.ldap.object.trustSerialData 和 com.sun.jndi.rmi.object.trustURLCodebase,因此你不应单独依赖 JDK 版本。它可能会阻止最初的浪潮,但有人找到一个聪明的小工具来解决它只是时间问题。
- 最后的方法是从类路径中删除 JndiLookup 类,但这是我们不推荐并且尚未验证的方法。
这篇文章扩展了官方 Elastic 安全建议,深入探讨了 Elasticsearch 在多个平台和版本上的详细信息。 Logstash 和 Elastic APM Java 代理也受到影响,但不是本文的一部分。
这篇文章扩展了官方 Elastic 安全建议,深入探讨了 Elasticsearch 在多个平台和版本上的详细信息。 Logstash 和 Elastic APM Java 代理也受到影响,但不是本文的一部分。
这对 Elasticsearch 意味着什么?
Elasticsearch 5.0 到 7.16.0 的所有版本都使用易受攻击的 Log4j2 版本——请参阅下面的 “Elasticsearch 使用的是什么版本的 Log4j?”。
但由于最初随 Elasticsearch 2.0 引入的 Java 安全管理器,它不是 Elasticsearch 7.x 和 6.x 上的 RCE。安全管理器通过一个严格限制 SocketPermission 的 security.policy 文件再次拯救了我们,并且只在几个地方授予它,比如我们的网络库 Netty。从日志库中加载数据或远程代码是不可能的——这通常是有意义的并且现在得到了回报。
仍然存在通过 DNS 泄露信息的潜在风险,因为这是全球允许的。但是,这有两个限制:
- JVM 版本降低了风险,因为我们无法在 JDK 9 或更高版本上重现泄漏。请参阅下面的 “Elasticsearch 使用的是什么版本的 JVM?”。
- 泄漏无法公开 Elasticsearch 数据,而只能公开可通过 Log4j2 查找读取的数据,例如环境变量和来自其他来源的一组有限环境数据。如果你已将 AWS 秘密设置为环境变量(通常在 Elasticsearch 服务器上不需要),这可能是一个令人担忧的原因。
Elasticsearch 5.x 容易受到 RCE 和信息泄漏的影响,你需要紧急采取缓解措施。对于 ≥ 5.6.11,你可以使用 log4j2.formatMsgNoLookups=true 作为修复。不幸的是,5.x 的安全管理器规则不像 6.0 以来那么严格。
关于使用防火墙、仅绑定到 localhost(Elasticsearch 中的默认值)或使用 “未知”端点(如 Elastic Cloud 中)的最后注意事项:如果你的应用程序将未经处理的字符串传递给 Elasticsearch,则这些字符串可以在那里为你提供保护被记录。
我现在应该怎么办?
为了安全起见,请尽快升级到 Elasticsearch ≥ 7.16.1 或 ≥ 6.8.21。这些版本在 JVM 选项中设置 -Dlog4j2.formatMsgNoLookups=true 并为你删除 JndiLookup 类 – 链接里的提交位于主分支上,但已向后移植。
如果你无法升级,请开始考虑按照上面的方法到达那里。除了性能改进或新功能之外,此事件不是最后一个或唯一的安全问题。
如果你仍然无法升级,你应该应用 JVM 选项 log4j2.formatMsgNoLookups=true 如果你正在使用 Elasticsearch ≥ 6.4.0 或 ≥ 5.6.11 — “Elasticsearch 使用的是什么版本的 Log4j?”下面解释了原因。如果你使用 JDK 9 之前的版本— “Elasticsearch 使用的是什么版本的 JVM?”有更多的细节。以下部分显示了如何应用设置。
如何在旧版本上应用 JVM 设置?
在将 log4j2.formatMsgNoLookups=true 应用于 ≥ 6.4.0 或 ≥ 5.6.11 的几个不同 Elasticsearch 安装之前——你如何验证该设置已被应用? Kibana 控制台中的 curl -XGET “http://localhost:9200/_nodes/jvm?pretty” 或 GET _nodes/jvm 请求包含每个节点的 input_arguments 数组。必须在每个节点上设置 log4j2.formatMsgNoLookups=true 并通过重新启动应用以完成其工作。
有关以下示例涵盖的更多详细信息,请阅读有关设置 JVM 选项的文档。
ZIP (macOS ARM)
使用 ES_JAVA_OPTS=”-Dlog4j2.formatMsgNoLookups=true” ./bin/elasticsearch 从解压后的 TAR.GZ 的根文件夹启动 Elasticsearch。
或者通过将文件添加到 config/jvm.options.d/ 来实现。实现方法类似于接下来的一种方法。
Linux 服务 (Ubuntu)
不要直接编辑 /etc/elasticsearch/jvm.options,因为它可能会被更新覆盖。相反,在 /etc/elasticsearch/jvm.options.d/ 中创建一个文件。例如 /etc/elasticsearch/jvm.options.d/log4j2.options 内容如下,然后重启 Elasticsearch 服务:
# CVE-2021-44228
-Dlog4j2.formatMsgNoLookups=true
Docker
将 ES_JAVA_OPTS 设置为环境变量的最小示例:
docker run
--publish 127.0.0.1:9200:9200
--env ES_JAVA_OPTS="-Dlog4j2.formatMsgNoLookups=true"
--env discovery.type=single-node
--volume='elasticsearch:/usr/share/elasticsearch/data'
docker.elastic.co/elasticsearch/elasticsearch:7.16.0
或者,你可以将自定义 JVM 选项文件绑定到 /usr/share/elasticsearch/config/jvm.options.d/ 类似于上面的 Ubuntu 示例。
Kubernetes with ECK
使用 ES_JAVA_OPTS 自定义 podTemplate 的最小示例:
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: quickstart
spec:
version: 7.16.0
nodeSets:
- name: default
count: 1
podTemplate:
spec:
containers:
- name: elasticsearch
env:
- name: ES_JAVA_OPTS
value: "-Dlog4j2.formatMsgNoLookups=true"
如果我卡在很老版本怎么办?
如果你使用 5.0.0 到
我在 6.0.0 上尝试了两种不同的 hack,但我们仍在评估是否要立即对此进行更多宣传。
我可以在不升级和重新启动的情况下解决问题吗?
不止我所知道的。 Volker Simonis 创建了 Log4jHotPatch。 但是我一直无法将它应用到 Elasticsearch,因为——你可能已经猜到了——安全管理器。
我只在带有动态代理的 JDK 8 上尝试过,遇到了以下问题:
Caused by: java.security.AccessControlException: access denied ("java.util.PropertyPermission" "log4jFixerAgentVersion" "write")
: Commenting out theproperty writingfixes this one.Caused tgcodeby: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.jdk.internal.org.objectweb.asm")
: Not sure there is a way around that one.
如果你找到方法,请告诉我。
Elasticsearch 使用什么版本的 Log4j?
过去三年的任何版本的 Elasticsearch 都使用 Log4j 2.11.1(截至 2021/12/13)。你可以在 GitHub 上的源代码中检查 8.0、7.16、7.13 之后哪些文件被移除、6.8 和 5.6。
长期以来一直存在升级 Log4j2 的 PR 请求,该请求在 Elasticsearch 使用 Java 安全管理器时遇到了权限问题。因此,虽然安全管理器可以使事情变得更复杂,但它停止了有关此漏洞的远程代码执行部分,这感觉是一个合理的权衡。tgcode此外,此升级中的版本同样容易受到攻击,因此不会对当前的安全问题产生影响。
2018 年 8 月之前的版本使用 Log4j 2.9.1,这意味着在 Elasticsearch 5.6.11 和 6.4.0 之前。这些版本不能使用 log4j2.formatMsgNoLookups=true 缓解,因为该选项是后来才添加的。
Elasticsearch 5.0 与 2.6.2 版一起发布。 Elasticsearch 的早期版本一直使用 Log4j 1.x,它不易受到这种攻击,但不再受支持,并且可能包含其他安全问题。
Elasticsearch 使用什么版本的 JVM?
默认情况下,从 Elasticsearch 7.0.0 上的 JVM 是捆绑下载的。 在以下情况下,你需要检查你的自定义 JVM 版本:
- 你使用的是 7.0.0 之前的版本(包括任何 6.x 版本)。
- 你正在使用不包含 JDK 的二进制文件。
- 你正在设置自定义 ES_JAVA_HOME(或早期 7.x 版本中的 JAVA_HOME)。
你可以再次在 Kibana 的控制台中使用 curl -XGET “http://localhost:9200/_nodes/jvm?pretty” 或 GET _nodes/jvm 从 Elasticsearch API 检查 JVM 版本。 部分响应将显示如下内容(来自 Elastic Cloud 上的 7.16.0):
"jvm" : {
"pid" : 268,
"version" : "17.0.1",
"vm_name" : "OpenJDK 64-Bit Server VM",
"vm_version" : "17.0.1+12",
"vm_vendor" : "Eclipse Adoptium",
"bundled_jdk" : true,
"using_bundled_jdk" : true,
Elasticsearch 频繁升级捆绑的 JDK 版本; 例如,7.16 使用的是 JDK 17.0.1+12。 但即使 7.0.0 是在 JDK 12+33 上,所以 7.0.0 上的捆绑 JDK 都没有使用易受攻击的 JVM 设置。
但是,有两个警告:
- Elastic Cloud 在 Elasticsearch 7.2 之前使用了较旧的 JDK。 建议尽快在任何此类集群上执行 “无停机重启”,这将自动应用 log4j2.formatMsgNoLookups=true 缓解措施。 使用 Elasticsearch 7.1.0 auf Elastic Cloud 的 JVM 版本示例:
"jvm" : {
"pid" : 611,
"version" : "1.8.0_144",
"vm_name" : "Java HotSpot(TM) 64-Bit Server VM",
"vm_version" : "25.144-b01",
"vm_vendor" : "Oracle Corporation",
"bundled_jdk" : true,
"using_bundled_jdk" : false,
- Elasticsearch Docker 镜像总是捆绑了一个 JDK。 从 Elasticsearch 6.6.0 开始,这些镜像已经在 Elasticsearch 存储库中,并且至少使用了 JDK 11.0.1。 旧版本需要对现已存档的存储库进行更新。 从 1.8 到 JDK 10(我们似乎从未随 JDK 9 一起提供镜像)的变化发生在 Elasticsearch 5.4.0 镜像的发布中。 如果你还在使用 5.4.0 之前的 Docker 镜像,你应该认真考虑升级。
不推荐使用 Java 安全管理器吗?
是的。 Java 安全管理器在 JDK17 中已被弃用,在 JDK18 中将成为空操作——有关详细信息,请参阅 JEP 411。
如果 Log4Shell 显示了任何内容,那么这就是在你的应用程序中拥有沙箱概念的价值。为什么你的日志库应该能够进行网络调用?像 SELinux 或 seccomp 这样的概念是更大图景的一部分,但对于这个特定要求来说太生硬了。如需进一步阅读,请参阅 Twitter 上的讨论,其中一些人在保护 Java 应用程序(如 Elasticsearch)方面花费了大量时间。
虽然我们宁愿不在那种情况下,但 Elasticsearch 团队已经在研究新的安全机制。
我可以采取其他措施来保护 Elasticsearch 吗?
额外的安全层会增加你部分或完全减轻这种攻击的机会。其中一些层可能是:
- 清理输入:例如使用 Web 应用程序防火墙 (WAF);尽管它增加了潜在的性能问题和误报的风险。
- 传入防火墙规则:对于内部应用程序等用例,尽可能限制对 Elasticsearch 和你的应用程序的访问。
- 传出防火墙规则:你的 Elasticsearch 节点只需要对有限的一组端点(如 Elasticsearch 集群中的其他节点、其快照存储库、你的应用程序、Elastic Stack 的其他部分)进行网络访问,并下载必要的二进制文件(这甚至可能是限于安装和升级的时间)。
Elasticsearch 通过始终提供当前版本的 JVM、使用 Java 安全管理器、使用 seccomp、不允许以 root 身份运行或在 8.0 中默认启用安全性来尽自己的一份力量。
如果有什么要纠正的,请给我留言。
这同样适用于问题或评论 – 如果你有任何疑问,请继续提问。
文章来源于互联网:在 Elasticsearch 中缓解 Log4j2/Log4Shell