2025年2月9日 星期日

Java 7 to 17 DeserializationFilters

一、前言

一、前言

返回目錄

Java 的序列化與反序列化機制,允許將對象的狀態轉化為字節流,並從字節流重新構建對象。 然而,這種強大的功能也帶來了潛在的安全風險,特別是當反序列化來自不可信來源的數據時。 缺乏適當的安全措施,攻擊者可能利用反序列化漏洞執行任意代碼,造成嚴重後果。

在 Java 7 及更早版本中,保護反序列化安全主要依賴於在反序列化前驗證輸入流,或使用自定義的反序列化邏輯。 這些方法往往複雜且容易出錯。

自 Java 7 起,Java 逐步引入了反序列化過濾器 (Deserialization Filters) 機制,旨在提供更安全、更可控的反序列化流程。 從 Java 9 開始,該機制得到完善,允許開發者定義全局和特定於流的過濾器,以更有效地控制反序列化過程。 Java 15 进一步增强了过滤机制,使其更易用、高效。

本文整理 Java 7 至 17 關於反序列化過濾器的新特性,並提供範例,以助開發者理解和使用這些特性,提升應用程序的安全性。

目錄



二、反序列化的安全風險

返回目錄

在深入了解反序列化過濾器之前,我們快速回顧反序列化的安全風險。

  • 任意程式碼執行 (Remote Code Execution, RCE): 最嚴重的風險,攻擊者可以精心構造惡意的序列化數據,在反序列化時觸發任意程式碼執行。 通常,這是透過利用應用程式中存在的類別,例如 CommonsCollections Spring 等函式庫中的 gadget chains (物件鏈) 來實現。

  • 阻斷服務 (Denial of Service, DoS): 攻擊者可以發送大量、複雜的序列化數據,導致服務器資源耗盡 (例如 CPU 或記憶體),造成阻斷服務攻擊。

  • 資料外洩 (Data Leakage): 攻擊者可以控制反序列化過程,讀取敏感資料,例如密碼或私鑰。

三、Java 7 - 8 的初步安全措施

返回目錄

Java 7 和 8 雖然沒有正式的反序列化過濾器 API,但開發者可以採取一些安全措施:

  • 黑名單 (Blacklisting): 限制可以反序列化的類別。 黑名單容易被繞過,因為攻擊者可以尋找不在黑名單上的其他類別來觸發漏洞。
  • 白名單 (Whitelisting): 僅允許反序列化特定的類別。 白名單更安全,但需要仔細維護允許的類別清單。
  • 自定義 readObject() 方法: 在類別的 readObject() 方法中添加驗證邏輯,檢查反序列化後的對象狀態是否有效。

範例 (Java 8):

架構:

四、Java 9:引入反序列化過濾器 (Deserialization Filters)

返回目錄

Java 9 引入了 java.io.ObjectInputFilter 介面,標誌著反序列化過濾器機制的正式誕生。 該介面允許開發者定義規則,用於判斷是否允許反序列化某個類別或物件。

核心概念:

  • ObjectInputFilter : 核心介面,定義了 checkInput() 方法,用於檢查反序列化的類別或物件。(Java 9 之前的版本是 check() )
  • ObjectInputStream.setObjectInputFilter(ObjectInputFilter filter) : 用於設定特定於流的過濾器。
  • java.io.ObjectInputFilter.Config.setSerialFilter(ObjectInputFilter filter) : 用於設定全局過濾器 (JVM 層級)。

範例 (Java 9):

執行結果:

序列化檔案:

架構:

工具:

  • 可以使用 ObjectInputFilter.Config.createFilter(String pattern) 快速建立簡單的過濾器。
  • 可以透過設定 JVM 參數 -Djdk.serialFilter=pattern 設定全域過濾器。

五、Java 15:運用自訂 ObjectInputFilter 進行精細控制

返回目錄

Java 15 雖然沒有引入全新的 API 來 簡化 反序列化過濾器的設定,但它延續了反序列化過濾器機制的發展,鼓勵開發人員採用更精細的安全控制。 Java 15 強調透過自訂 ObjectInputFilter 來實現更靈活的反序列化策略,允許開發人員根據應用程式的需求來定義特定的限制和驗證規則。 雖然 ObjectInputFilter.Config.createFilter(String pattern) 方法仍然可用於簡單的基於類別名稱的過濾,但本範例將展示如何建立一個自訂的 ObjectInputFilter 來控制反序列化的深度、引用數量和大小。

原因:

Java 15 鼓勵使用自訂的 ObjectInputFilter 主要有以下幾個原因:

  • 更強大的控制: 自訂過濾器允許您根據應用程式的具體需求來設定反序列化的限制。您可以根據物件的屬性、環境變數或其他任何可以存取的資訊來做決策。
  • 更高的靈活性: createFilter 方法僅支援基於類別名稱的簡單模式比對。 自訂過濾器則可以執行更複雜的邏輯,例如根據物件的狀態、網路位置或任何其他可用的上下文來允許或拒絕反序列化。
  • 明確的安全策略: 透過自訂過濾器,您可以更清楚地定義和實施您的安全策略。 這有助於確保您的應用程式僅反序列化您信任的物件,並避免潛在的漏洞。

範例 (Java 15):

說明:

  1. MyFilter 類別: 這個類別實作了 ObjectInputFilter 介面,並包含一個 limits Map,用於儲存深度、引用數量和大小的限制。
  2. checkInput 方法: 這個方法是過濾器的核心。它會檢查反序列化的深度、引用數量和大小是否超過了設定的限制。 如果超過了限制,則返回 Status.REJECTED
  3. parseLimits 方法: 這個方法用於解析過濾器字串,並將限制儲存在 limits Map 中。
  4. filterPattern 字串: 該字串現在用於傳遞各個限制參數,同時也用來判斷是否允許 SerializableObject

總結:

雖然 Java 15 並未提供新的 簡化 API,但其強調使用自訂 ObjectInputFilter 反映了 Java 反序列化安全性的發展趨勢:朝向更精細的控制和更靈活的安全策略。 透過建立自訂過濾器,開發人員可以更好地保護其應用程式免受反序列化漏洞的侵害。

注意事項:

  • 本範例未直接使用 ObjectInputFilter.Config.createFilter(String pattern) 方法,因為它無法提供所需的精細控制。 鼓勵開發人員仔細評估他們的安全需求,並選擇最適合的過濾器建立方法。
  • 使用 createFilter 方法只適用於簡單的基於類別名稱的過濾,如果要實現更複雜的過濾邏輯,例如基於狀態的過濾,或者基於資料內容的過濾,就需要自訂 ObjectInputFilter

執行結果:

序列化檔案:

在上面的例子中, filterPattern 字串使用了 maxdepth , maxrefs , maxbytes 屬性,用於限制反序列化的深度、引用數量和總大小。

六、Java 17 及以後的發展趨勢

返回目錄

Java 的反序列化過濾器機制仍在不斷發展。 預計未來會更加強調:

  • 更精細的控制: 允許開發者定義更複雜的過濾規則,例如基於物件狀態的過濾。
  • 更易用性: 提供更簡潔的 API 和配置方式。
  • 更強的安全性: 提供更強大的防禦機制,防止新型反序列化攻擊。
  • GraalVM Native Image 的支援: 針對 GraalVM Native Image 的序列化/反序列化優化和安全性加強。

七、最佳實踐

返回目錄

  • 始終使用反序列化過濾器: 無論是應用程式還是函式庫,都應啟用反序列化過濾器,降低安全風險。
  • 採用白名單方法: 僅允許反序列化必要的類別,避免使用黑名單。
  • 限制反序列化的深度、引用數量和大小: 防止阻斷服務攻擊。
  • 定期更新 Java 版本: Java 新版本通常包含反序列化過濾器方面的安全修補程式和改進。
  • 審查序列化數據的來源: 避免反序列化來自不受信任的來源的數據。
  • 考慮使用替代方案: 在允許的情況下,避免使用 Java 序列化。 可以考慮使用 JSON、Protocol Buffers 或 Apache Avro 等更安全的序列化方案。

八、總結

返回目錄

Java 7 至 17 引入的反序列化過濾器機制,為開發者提供了更安全、更可控的反序列化流程。 從最初的黑名單和白名單方法,到 Java 9 的 ObjectInputFilter 介面,再到 Java 15 的簡化配置 API,Java 的反序列化安全機制在不斷演進。

開發者應充分利用這些特性,並遵循最佳實踐,提升應用程序的安全性,降低反序列化攻擊的風險。 始終記住,反序列化的安全性是一個持續的挑戰,需要不斷學習和更新,才能有效地防範新型攻擊。 並且關注未來 GraalVM Native Image 相關的特性更新。

沒有留言:

張貼留言