首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 序列化進階:你可能不知道的 5 件事(二)——重構相容性與安全性陷阱

     編輯:Java 相關知識

1. 序列化允許類別重構演進

Java 序列化規範自動支援以下向後相容變更,ObjectInputStream 仍能正確讀取:

  • 新增欄位
  • 將 static 改為非 static
  • 將 transient 改為非 transient

若需移除欄位或將非 static/transient 改為 static/transient,則需額外處理。關鍵在於 serialVersionUID:序列化依據類別結構產生雜湊值,版本演進時必須保持相同 UID。可透過 serialver 工具取得原始類別的 UID,明確宣告於新版本中:

private static final long serialVersionUID = 1234567890L;

擁有相同 UID,即可雙向相容:舊資料反序列化為新類別(新欄位為預設值),新資料反序列化為舊類別(多餘欄位被忽略)。

實例:Person 類別新增 Gender 欄位

enum Gender { MALE, FEMALE }

public class Person implements java.io.Serializable {
    private static final long serialVersionUID = 1234567890L; // 固定 UID
    private String firstName, lastName;
    private int age;
    private Person spouse;
    private Gender gender; // 新增欄位

    // 建構子、getter/setter、toString()...
}

2. 序列化並不安全

Java 序列化二進位格式完全公開且可逆。直接將序列化流輸出到主控台,即可看到類別結構與私有欄位內容。透過 RMI 傳輸物件時,私有欄位幾乎以明文出現在 Socket 流中,存在資安風險。

解決方案:Hook 序列化過程模糊化敏感資料

實作 writeObject 與 readObject 方法,在序列化前/反序列化後轉換敏感欄位:

private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
    age <<= 2;                 // 序列化前:年齡左移 2 位(簡單模糊化)
    out.defaultWriteObject();
}

private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
    in.defaultReadObject();
    age >>= 2;                 // 反序列化後:還原年齡
}

注意:方法簽名必須完全符合規範(private、參數型別、拋出例外),否則 JVM 會靜默忽略,導致資料洩露。此技巧僅為示範,實務應使用強加密演算法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved