12 月 10 日凌晨,Apache 开源项目 Log4j 的远程代码执行漏洞细节被公开,由于 Log4j 的广泛使用,该漏洞一旦被攻击者利用会造成严重危害。
Log4j 是一个被许多 Java 应用程序使用的库,它是迄今为止最普遍的 Java 库之一。Log4j 安全问题围绕 Log4j 库中的一个错误展开,该错误可能允许攻击者在使用 Log4j 写出日志消息的系统上执行任意代码。这个安全漏洞影响广泛,该漏洞一旦被攻击者利用会造成严重危害。
随着 Log4j 安全漏洞问题的持续发酵,一些天天唱衰 Java 的家伙,又开始借助这一漏洞问题将矛头指向 Java。他们总爱发文发帖、强调这种已经拥有 25 年历史的顶级编程语言就快不行了。不过每次 Java 都能挺过来,继续为全球无数开发者服务。这里我先要承认,不少安全厂商针对 log4j2 漏洞利用原理发布的文章确实意义重大。这个安全问题确实值得大家保持关注,也推荐各位尽快根据建议审查自己的 Java 项目是否存在隐患。
在本文中,我想着重聊聊 Java 生态系统,探讨日志记录框架是什么、为什么/该怎么使用这些框架,以及开发团队要如何观察并控制自己 JVM 的活动模式。
Java 开发者们的安全责任
Java 开发者们应该如何保证安全性?答案很简单——只要快速修复 JDK 和库,我们就能规避大多数潜在的普遍性违规问题。
修复库(必选)
一旦发现库内存在漏洞,最有效的方法当然是修复库以消除漏洞。若不及时修复,你的应用程序很可能被黑客入侵,攻击者将获得对目标系统及其数据的完全访问权限。
而无论面对什么状况,修复都是最有效的应对手段。
日志框架可以来自任何依赖项——既可以是传递依赖项(由其他库添加),也可以是直接依赖项(由你自己添加)。我们可以使用 Contrast Community Edition 等分析工具检查当前依赖项及其他自定义漏洞。
此外,Maven dependency tree (dependency:tree) 与 Gradle dependency tree 也都是很好的开源依赖项分析工具。NetBeans 等 IDE 则提供依赖项关系图可视化工具。只要升级至 2.15.0 或更高版本,log4j2 漏洞就不会再骚扰各位。
按照 Java 安全基准(推荐、定期)修复 JRE
各个 Java 主版本都会维护一套持续性的安全基准。由于 JDK 每个季度都会通过新一轮安全改进实施修复,所以这套基准也在持续前进。换言之,任何低于当前安全基准的 Java 安装包都包含某些已知安全问题,应立即进行更新。
当然,这只是标准的安全最佳实践,与 log4j2 库漏洞没有直接关系、也解决不了这个漏洞。
但开发团队仍然应该使用 Foojay Disco API 自动监控安全基准并升级现有系统。开发人员可以将其与 GitHub 操作匹配起来,确保代码中的每个 build 都切实引入了最新安全更新。而一旦安全事件出现,升级 JRE 与代码的重构与重新部署也将同步进行。
Java 安全基准会在每年 1 月、4 月、7 月和 10 月最靠近 17 号的那个星期二迎来更新。详细信息请参考 Oracle 重要补丁更新计划,具体方式与 OpenJDK 漏洞组保持相同。当然,有时候即使没有大问题、官方也可能提供计划外的安全更新。Log4j2 并不属于此类。
下面我们以 Java 11 中的安全基准配置为例:
jobs:
java11:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
update: [x]
package: [jdk, jre]
fail-fast: false
max-parallel: 4
name: ${{ matrix.package }} 11.0.${{ matrix.update }}, ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Set up JDK 11 Zulu
uses: foojayio/setup-java@disco
with:
java-package: ${{ matrix.package }}
java-version: 11.0.${{ matrix.update }}
distro: zulu
- name: java -version
run: java -version
复制代码
定期检测自定义安全漏洞(测试中,推荐)
自动化安全工具能帮助我们在缺乏相关知识时仍准确捕捉到安全漏洞。通过将集成代理添加至 Java 应用程序当中,大家即可对应用程序中记录的安全信息进行被动检测。与前文提到的分析依赖项编号以确定是否存在漏洞的工具不同,这些自动化安全工具虽然也会跟踪同样的依赖项信息,但会通过集成分析器告知各现有库间的组合效果、特别是配合使用是否安全。
例如,集成分析器并不会简单查看是否存在 log4j2 漏洞及其版本,而是检测远程输入记录功能是否会被攻击者所控制。
此外,Contrast Community Edition 等免费分析工具也能捕捉 log4j2 零日漏洞及其他多种安全缺陷的行踪,例如:
-
我的应用程序中是否包含 SQL 注入缺陷,例如在 Hibernate、JBDC 或者其他位置?
-
远程攻击者能否控制发送至 Runtime.exec 的任何输入,进而导致命令注入漏洞?
-
我的应用程序中使用到哪些加密算法,具体用在何处、是否符合适当的安全标准?
-
我们是否正以某种非常规、有风险的方式组合不同库,例如 OGNL 输入解析?
使用 JDK Flight Recorder 监控安全事件
JDK Flight Recorder 是各类现代 OpenJDK 发行版中普遍提供的性能分析工具,能够以低资源成本提供安全信息。开发团队可以使用 JDK Flight Recorder 记录下诸多 IO 操作,例如 JRE 访问过哪些文件、或者哪些类与反序列化配对。
通过使用 JDK Flight Recorder 监控 Java 应用程序事件,并将事件流传输至安全信息与事件管理(SIEM)系统当中,Java 团队即可监控异常行为并/或是将已知安全类同 Java 反序列化过滤器相配对,因此防止漏洞利用行为。
哪些安全努力不值得尝试
以 log4j2 场景为例,Web 应用程序防火墙(WAF)等类似的网络防御方案虽然在短期内会有一定效果,但整体表现不佳而且工作量极为巨大。
-
网络防御成效捉急。大家可能都听过网上流传的段子,有人用 Photoshop 精心设计出一张看似正常、似藏玄机的车牌,识别系统一扫就会遭遇注射攻击。这办法绝了,因为开发者知道车牌识别系统会尝试解析和记录一切通过计算机视觉捕捉到的内容,而且这部分注入数据压根不用经过网络层。同样的,大多数应用程序也会有针对性地使用部分数据、解码数据并记录下各类细节。很明显,任何网络工具都没办法覆盖到如此广泛的攻击面。
-
监控并跟踪攻击者,第一时间屏蔽其 IP 同样效果不佳。虽然有些组织会坚持维护一套潜在攻击者清单,但 AWS IP 之所以被命名为 Elastic(弹性),正是因为它们会定期更改。即使拉黑一个,对方要么可以等自然解禁、要么就是换个 IP 继续攻击。
系统属性与动态补丁:效果尚可
我们可以使用几个系统属性与补丁控制住 log4j2 的肆意活动。如果暂时无法更新库或者依赖项,那这些就是最合理的过渡性安全问题。
两项 Java 系统属性:
-
Dcom.sun.jndi.rmiobject.trustURLCodebase=false
-
Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false
将它们设置为 false 即可阻止远程加载。
另有一个动态补丁能够接入当前运行的 JVM 并执行修复。它的问题是,我们每次启动 JVM 都需要再次运行此补丁。在一部分用例中这样就够了,只是肯定不如直接更新库来得方便。
Java 是如何处理日志记录的?
Java 开发者通常会从多种日志记录系统和外观中做出选择。随着社区的多年发展、合并和交融,各类日志记录框架往往已经能够彼此协同运作:
-
System Logger (2017 年,推荐)在 JDK 9 中被首次引入。它改进了 JDK Logger 的 API,并提供类似于 SLF4j 的外观,能够将 JDK 日志重新定向至应用程序团队指定的记录器处。
-
JDK Logger (2004 年)于 Java 1.4 版本中被引入。它特别常见,只是 API 显得有点陈旧了。虽然也能用,但不像其他日志记录框架那么灵便。
-
Log4j与Log4j2 属于社区开发的记录器。它们改进了 API,让团队能够轻松控制需要记录的内容、检索特定数据何时出现在哪些层级。
-
Logback 与SLF4j 也是两款颇具人气的记录器。SLF4J 属于一套相对简单的日志记录外观,可帮助团队管理其他多种记录器——库维护人员将直接登录到 SLF4J,之后再由应用程序开发人员具体配置要使用哪些底层记录器提供统一的输出结果。除了高质量 AIP 之外,二者还最大限度减少了我们需要面对的依赖项。
-
JBoss Logger 是 JBoss 生态系统中的另一款流行记录器,运行状态稳定且速度很快。它现在已经能够支持 Quarkus 等多种其他日志记录框架。
-
Apache Commons-Logging(2002 年)的历史比 JDK Logger 更长,也启发了后来诸多 API。它的最后一个版本发布于 2014 年,之后随着从单一项目向跨项目 API 的用户趋势变化而没落。
2022 年最推荐的 Logger 方案
对于依赖项较少、发布时间不长的新兴项目,这里建议大家优先考虑 System Logger。对于包含大量依赖项的项目,我们则建议继续遵循大部分依赖项的对接的既有记录器、或者使用统一的日志记录外观(门面)。
如果你之前并没有使用任何记录器,则可以把 System Logger 当成是具有良好 API 的 JDK Logger 来使用。