Java 作為頂級程式設計語言之一,已經在企業級軟體開發領域活躍 25 年了。有人不斷宣傳 Java 已死,同時也有人堅稱 Java 活得好好的。最近,又有報道稱 log4j 2 漏洞将再次“殺死” Java。
我們曾開玩笑說,Java 博物館就好像是一個墓園,記錄了每一次“死亡”的經過。
作者:Erik Costlow
譯者:彎月
連結:https://foojay.io/today/log4j-isnt-killing-java/
上周,技術圈被 log4j 2 漏洞掀起巨浪,各大安全公司紛紛發文介紹該漏洞的危害,并給出了各種臨時解決方案。還有一些部落客也發表文章教我們如何找到易受攻擊的地方,并采取相應的防禦措施。還有大量文章跟着起哄,讨論如何采用一些不必要的防禦技術。
目前,log4j 2 官方團隊已釋出 2.16.0 新版本,加強漏洞防禦機制。log4j 2 是一款基于 Java 研發的開源日志系統,是以,當史詩級漏洞被爆出後,便有人宣稱 log4j 2 漏洞将再次“殺死” Java,已經被“死亡”過無數次的 Java,就像是開了一個墓園,記錄每次“死亡”經過。
本文将簡單介紹一下 Java 生态系統,說明什麼是日志記錄架構、在何處使用以及使用的原因,此外,還将介紹各個團隊應當如何觀察和控制 JVM 的行為。

快速給 JDK 和庫打更新檔是目前最有效的技術,可避免絕大多數大規模的黑客攻擊。
當代碼庫中存在漏洞時,最有效的技術就是打更新檔以去除漏洞。如果不給庫檔案打更新檔,那麼應用程式很有可能被黑客入侵,攻擊者将獲得系統及其資料的完整通路權限。
無論在何種情況下,通常打更新檔都很有效。
日志架構可能來自任何依賴項,可能由另一個庫引入(即傳遞依賴項),而非由開發人員添加(即直接依賴項)。我們可以使用依賴項分析工具,例如 Contrast Community Edition,來檢測依賴項和其他自定義的漏洞。
此外,還有一些分析依賴關系的開源工具,比如 Maven 依賴樹(dependency:tree)和 Gradle 依賴樹。NetBeans 等 IDE 也提供了依賴關系圖可視化工具。
對于 log4j2 漏洞,你必須更新到 2.15.0 或更高版本。
每個Java 主要版本都會維護一個安全基線。由于每個季度 JDK 都會提供帶有新安全改進的更新檔,是以這個安全基線也會不斷向前移動。低于安全基線的 Java 包含已知的安全問題,應該更新。
這是标準的安全最佳實踐,與 log4j 2 漏洞沒有直接關系,也不會修複該漏洞。
各個團隊可以使用 Foojay Disco API 自動監控安全基線,并及時地更新系統。開發人員可以将這個更新與 GitHub 操作相結合,確定在每次建構代碼時,都使用最新的安全更新。如果發生安全事件,則立即更新 JRE,同時重新建構并重新部署代碼。下面這個測試矩陣中就包含了這類的 GitHub 操作(https://github.com/foojayio/discoTestingMatrix)。
Java 安全基線的更新時間為:每年 1 月、4 月、7 月和 10 月,17 日前後的周二。詳細資訊包含在Oracle 重要更新檔更新計劃(https://www.oracle.com/security-alerts/)中,OpenJDK 漏洞組(https://foojay.io/pedia/security-vulnerability-management/)也采用了同一個計劃。此外,如果出現重大問題,Oracle 還會提供計劃外的安全更新。但 log4j 2 漏洞不屬于這種情況。
以下配置示範了如何使用 Java 11 的安全基線:
自動化安全工具可以捕獲安全漏洞,不需要安全專業知識。将這類安全工具內建到 Java 應用程式,就可以實作安全監測,并記錄安全資訊。有些工具會根據依賴項的數量來決定是否存在漏洞,而這種方法則會根據依賴資訊,由內建的分析器來報告這些依賴庫的組合情況,并判斷組合後是否安全。
例如,內建分析器不隻是簡單地檢查 log4j2 存在與否及其版本,而且還可以确定攻擊者是否可以控制遠端日志輸入。
此外,Contrast Community Edition 之類的免費分析器還能夠即時捕獲 log4j 2,并捕獲許多其他的安全漏洞,例如:
應用程式的 Hibernate、JBDC 或任何其他地方是否包含 SQL 注入問題?
遠端使用者能否控制發送到 Runtime.exec 的任何輸入,即是否存在指令注入漏洞?
應用程式使用了哪些加密算法,在何處使用,是否符合适當的标準?
開發人員在結合使用多個庫時,是否意外引入了某個安全漏洞,例如 OGNL 輸入解析?
以及其他應用程式特有的安全漏洞。
JDK Flight Recorder 是現代 OpenJDK 發行版中包含的性能分析工具,它不僅可以生成一些安全資訊,而且開銷非常低。各個團隊可以使用 JDK Flight Recorder 來記錄許多 IO 操作,例如 JRE 通路了哪些檔案,或者哪些類會被反序列化。
通過使用 JDK Flight Recorder 監視 Java 應用程式事件,并通過資料流将事件傳輸到安全資訊和事件管理(Security Information and Event Management,即SIEM)系統中,Java 團隊就可以監視異常行為,并通過可防止漏洞的 Java 反序列化過濾器來檢查各個類是否安全。
對于 log4j 2 漏洞的問題,Web Application Firewall(WAF)之類基于網絡的防禦和工具可能在短期内有一定的效果,但通常都沒有太大作用,而且工作量非常大。
網絡防禦的效果不大。網上流傳着一個梗,一張經過 PS 的汽車照片,其車牌号上包含了一條注入工具。這個梗的點就在于,開發人員都知道,車牌号會通過計算機視覺分析後記錄到日志中。構成注入的資料并沒有出現在網絡層。同樣,大多數應用程式使用資料的不同部分,解碼資料并記錄各種資訊。任何網絡工具都無法比對足夠多的模式來檢測安全問題。
通過觀察和追蹤來阻止攻擊者 IP 的方法并不是特别有效。雖然有些團隊可能會維護一張攻擊者的清單,但 AWS IP 之是以被稱為彈性 IP,是因為這些 IP 會定期變化,是以,即便你阻止了某個 IP,過一段時間可能就又解鎖了,或者很快就會受到不同 IP 的攻擊。
圖:該圖示範了網絡層無法檢測到的漏洞
有幾個更新檔和系統屬性可以控制 log4j 2 的行為并阻止攻擊。有時候,有些庫無法及時更新,或者團隊在努力更新依賴項,但需要一定的時間,在這兩種情況下,就可以考慮這幾個更新檔和系統屬性。
相關的 Java 系統屬性有兩個:
-Dcom.sun.jndi.rmiobject.trustURLCodebase=false
-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false
将這兩個屬性設定為 false 可以阻止遠端攻擊。
還有一個動态的更新檔,它可以連接配接到正在運作的 JVM 并給其打更新檔。這個更新檔必須在 JVM 每次啟動時應用。雖然這兩種方法有一定的作用,但相較而言,更新庫更簡單。
Java 開發人員一般可以從多個日志系統和記錄方式中進行選擇。多年來,随着社群的發展,許多日志架構也可以協同工作了:
System Logger(2017 年推出,推薦)是 JDK 9 中引入的日志系統。它改進了 JDK Logger 的 API,并提供了類似于 SLF4j 的記錄方式,可以将 JDK 的日志重定向到應用程式團隊選擇的日志系統。
JDK Logger(2004 年推出)是 Java 1.4 中引入的日志系統。由于 JDK 中大量使用了該日志系統,是以變得很流行,但是 API 有點蹩腳。雖然這個日志系統也不錯,但不如其他架構。
Log4j 和 Log4j2 是社群推薦的日志系統,二者改進了 API,是以開發團隊可以更輕松地控制記錄的内容以及各個級别的日志記錄資料的方式。
Logback 和 SLF4j 也是流行的日志系統。SLF4J 是一個簡單的日志記錄方式,可幫助團隊處理許多日志記錄,庫的維護人員可以将日志輸出到 SLF4J,然後由應用程式開發人員配置他們将使用哪些底層的日志系統來統一輸出。此外 SLF4J 還建立了良好的 API,最大限度地減少了依賴關系。
JBoss Logger 是 JBoss 生态系統中的另一個流行的日志系統。該系統性能良好,而且運作速度很快。如今它還支援其他流行架構,如 Quarkus。
Apache Commons-Logging(2002 年推出)誕生于 JDK 日志系統之前,并啟發了許多 API。它的最後一個版本是于 2014 年推出的,之後人們陸續開始采用其他以支援良好的日志記錄為目标的 API。
依賴項越少越好,項目越新越好,是以我們可以考慮 System Logger。
有些項目擁有大量依賴項,但優勢在于它們使用的日志記錄工具與大多數的依賴項相同,隻不過選用了其他日志記錄方式。
如果你沒有任何日志系統,則可以考慮 System Logger,它是一款擁有良好 API 的 JDK 日志記錄工具。
日志架構能夠讓應用程式的主人看到通用格式的日志消息、時間戳、線程名稱以及其他資料。
此外,團隊可以将不同的輸出重定向到不同的位置,甚至無需顯示出來,例如,你可以将通路日志發送到一個檔案,将系統報告發送到其他地方,然後選擇顯示所有級别的日志資訊,或者動态檢視某個庫的調試資訊。