JAVA序列化和反序列化

轉自:http://blog.nsfocus.net/learning-guide-java-serialization-de-serialization-vulnerability-remediation

JAVA序列化和反序列化是啥?

在現有很多的應用當中,需要對某些對象進行序列化,讓它們離開內存空間,入駐物理硬盤,以便可以長期保存,其中最常見的是Web服務器中的Session對象。對象的序列化一般有兩種用途:把對象的字節序列永久地保存到硬盤上,通常存放在一個指定文件中;或者在網絡上傳送對象的字節序列。

而把字節序列恢復爲對象的過程稱爲對象的反序列化。當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據,而且無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個Java對象轉換爲字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復爲Java對象。

1

其實,在不同的計算機語言中,數據結構、對象以及二進制串的表示方式並不相同。對於像Java這種完全面向對象的語言,程序員所操作的一切都是對象,來自於類的實例化。

JAVA序列化和反序列化實例

在Java語言中最接近數據結構的概念,就是 POJO(Plain Old Java Object)或者Javabean。小編更熟悉Java語言,還是以此爲例說明一下序列化和反序列化的實現。

以上代碼說明:序列化Object成功後在M盤生成了一個object.txt文件,而反序列化Object是讀取M盤的Object.txt後生成了一個Object對象。

當然,並不是一個實現了序列化接口的類的所有字段及屬性,都是可以序列化的:

  • 如果該類有父類,則分兩種情況來考慮:如果該父類已經實現了可序列化接口,則其父類的相應字段及屬性的處理和該類相同;如果該類的父類沒有實現可序列化接口,則該類的父類所有的字段屬性將不會序列化,並且反序列化時會調用父類的默認構造函數來初始化父類的屬性,而子類卻不調用默認構造函數,而是直接從流中恢復屬性的值。
  • 如果該類的某個屬性標識爲static類型的,則該屬性不能序列化。
  • 如果該類的某個屬性採用transient關鍵字標識,則該屬性不能序列化。

那麼,在什麼情況下,需要自定義序列化的方式? 先舉個簡單的例子,如下:

如上代碼說明,可以得知,以下情況需要自定義序列化的方式:

  • 爲了確保序列化的安全性,可以對於一些敏感信息加密;
  • 確保對象的成員變量符合正確的約束條件;
  • 確保需要優化序列化的性能。

在序列化選型的過程中,安全性的考慮往往發生在跨局域網訪問的場景。當通訊發生在公司之間或者跨機房的時候,出於安全的考慮,對於跨局域網的訪問往往被限制爲基於HTTP/HTTPS的80和443端口。如果使用的序列化協議沒有兼容而成熟的HTTP傳輸層框架支持,可能會導致以下幾種結果:

  • 因爲訪問限制而降低服務可用性。
  • 被迫重新實現安全協議而導致實施成本升高。
  • 開放更多的防火牆端口和協議訪問,但是是以犧牲安全性爲前提。

反序列化漏洞危害

當應用代碼從用戶接受序列化數據,並試圖反序列化改數據進行下一步處理時,會產生反序列化漏洞,其中最有危害性的就是遠程代碼注入。

這種漏洞產生原因是,java類ObjectInputStream在執行反序列化時,並不會對自身的輸入進行檢查,這就說明惡意攻擊者可能也可以構建特定的輸入,在 ObjectInputStream類反序列化之後會產生非正常結果,利用這一方法就可以實現遠程執行任意代碼。

這個漏洞的嚴重風險在於,即使你的代碼裏沒有使用到Apache Commons Collections裏的類,只要Java應用的Classpath裏有Apache Commons Collections的jar包,都可以遠程代碼執行。

漏洞的根本問題其實並不是Java序列化的問題,而是Apache Commons Collections允許鏈式的任意的類函數反射調用。攻擊者通過允許Java序列化協議的端口,把攻擊代碼上傳到服務器上,再由Apache Commons Collections裏的TransformedMap來執行。

反序列化漏洞補救

2

現在,Apache Commons Collections在 3.2.2版本中做了一定的安全處理,對這些不安全的Java類的序列化支持增加了開關,默認爲關閉狀態。
涉及的類包括:CloneTransformer,ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer, PrototypeCloneFactory,PrototypeSerializationFactory, WhileClosure。
RedHat發佈JBoss相關產品的解決方案:https://access.redhat.com/solutions/2045023。

嚴格意義說起來,Java相對來說安全性問題比較少,出現的一些問題大部分是利用反射,最終用Runtime.exec(String cmd)函數來執行外部命令的。如果可以禁止JVM執行外部命令,未知漏洞的危害性會大大降低,可以大大提高JVM的安全性。
比如:

如上所示,只要在Java代碼裏簡單加一段程序,就可以禁止執行外部程序了。

禁止JVM執行外部命令,是一個簡單有效的提高JVM安全性的辦法。可以考慮在代碼安全掃描時,加強對Runtime.exec相關代碼的檢測。

小結

本文只是初步進行JAVA序列化和反序列化的科普,讓大家對此問題及相關補救方式有個直觀的印象和簡單瞭解,下一步深入解還請繼續關注綠盟技術博客。使用JAVA反序列化增多了數據的種類,但是還需要儘量避免使用反序列化的交互操作,減少風險的增加。目前,綠盟科技蜂巢社區啓動應急機制,已經實現遠程代碼執行漏洞的在線檢測。在社區中,大家可以進行網絡安全掃描插件的開發及討論。

其他相關參考資料:

Java反序列化漏洞被忽略的大規模殺傷利用


發佈了0 篇原創文章 · 獲贊 30 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章