1 Java安全之反序列化

序列化與反序列化概述Java序列化是指把Java對象轉換為字節序列的過程;這串字符可能被儲存/發送到任何需要的位置,在適當的時候,再將它轉回原本的 Java 對象,而Java反序列化是指把字節序列恢復為Java對象的過程 。
為什么需要序列化與反序列化當兩個進程進行遠程通信時,可以相互發送各種類型的數據 , 包括文本、圖片、音頻、視頻等,而這些數據都會以二進制序列的形式在網絡上傳送 。那么當兩個Java進程進行通信時,能否實現進程間的對象傳送呢?答案是可以的 。如何做到呢?這就需要Java序列化與反序列化了 。換句話說,一方面,發送方需要把這個Java對象轉換為字節序列 , 然后在網絡上傳送;另一方面,接收方需要從字節序列中恢復出Java對象
Java 提供了兩個類 java.io.ObjectOutputStreamjava.io.ObjectInputStream 來實現序列化和反序列化的功能 , 其中 ObjectInputStream 用于恢復那些已經被序列化的對象 , ObjectOutputStream 將 Java 對象的原始數據類型和圖形寫入 OutputStream 。
在 Java 的類中 , 必須要實現 java.io.Serializablejava.io.Externalizable 接口才可以使用,而實際上 Externalizable 也是實現了 Serializable 接口
ObjectOutputStreamObjectOutputStream 繼承的父類或實現的接口如下:

  • 父類 OutputStream:所有字節輸出流的頂級父類,用來接收輸出的字節并發送到某些接收器(sink) 。
  • 接口 ObjectOutput:ObjectOutput 擴展了 DataOutput 接口,DataOutput 接口提供了將數據從任何 Java 基本類型轉換為字節序列并寫入二進制流的功能,ObjectOutput 在 DataOutput 接口基礎上提供了 writeObject 方法,也就是類(Object)的寫入 。
  • 接口 ObjectStreamConstants:定義了一些在對象序列化時寫入的常量 。常見的一些的比如 STREAM_MAGIC、STREAM_VERSION 等 。
通過這個類的父類及父接口,我們大概可以理解這個類提供的功能:能將 Java 中的類、數組、基本數據類型等對象轉換為可輸出的字節,也就是反序列化 。接下來看一下這個類中幾個關鍵方法
writeObject這是 ObjectOutputStream 對象的核心方法之一,用來將一個對象寫入輸出流中,任何對象 , 包括字符串和數組,都是用 writeObject 寫入到流中的 。
之前說過,序列化的過程,就是將一個對象當前的狀態描述為字節序列的過程 , 也就是 Object -> OutputStream 的過程 , 這個過程由 writeObject 實現 。writeObject 方法負責為指定的類編寫其對象的狀態,以便在后面可以使用與之對應 readObject 方法來恢復它
writeUnshared用于將非共享對象寫入 ObjectOutputStream , 并將給定的對象作為刷新對象寫入流中 。
使用 writeUnshared 方法會使用 BlockDataOutputStream 的新實例進行序列化操作,不會使用原來 OutputStream 的引用對象 。
writeObject0writeObjectwriteUnshared 實際上調用 writeObject0 方法,也就是說 writeObject0是上面兩個方法的基礎實現 。具體的實現流程將會在后面再進行詳細研究 。
writeObjectOverride如果 ObjectOutputStream 中的 enableOverride 屬性為 true,writeObject 方法將會調用 writeObjectOverride,這個方法是由 ObjectOutputStream 的子類實現的 。
在由完全重新實現 ObjectOutputStream 的子類完成序列化功能時,將會調用實現類的 writeObjectOverride 方法進行處理 。
ObjectInputStreamObjectInputStream 繼承的父類或實現的接口如下:
  • 父類 InputStream:所有字節輸入流的頂級父類 。
  • 接口 ObjectInput:ObjectInput 擴展了 DataInput 接口,DataInput 接口提供了從二進制流讀取字節并將其重新轉換為 Java 基礎類型的功能,ObjectInput 額外提供了 readObject 方法用來讀取類 。
  • 接口 ObjectStreamConstants:同上 。
ObjectInputStream 實現了反序列化功能,看一下其中的關鍵方法 。
readObject從 ObjectInputStream 讀取一個對象 , 將會讀取對象的類、類的簽名、類的非 transient 和非 static 字段的值 , 以及其所有父類類型 。
我們可以使用 writeObjectreadObject 方法為一個類重寫默認的反序列化執行方,所以其中 readObject 方法會 “傳遞性” 的執行,也就是說,在反序列化過程中,會調用反序列化類的

推薦閱讀