需手动重写private writeObject与readObject方法实现敏感字段加密:先defaultWriteObject序列化非transient字段,再对transient敏感字段加密写入IV和密文;readObject中按序读取并解密还原,密钥须外部安全加载,禁用ECB,推荐AES/GCM。

直接在 writeObject 中手动加密敏感字段,不是加个注解或配个开关就能生效的事——它依赖你主动接管序列化流程,并严格配对反序列化解密逻辑。核心在于:用私有方法拦截默认行为,先让非敏感字段走默认序列化,再单独处理敏感字段的加密写入。
明确加密目标与字段隔离
先想清楚哪些字段真需要加密(如 password、idCard、token),再决定是否配合 transient 使用:
- 若字段声明为
transient,它不会被defaultWriteObject()自动写入,必须由你手动加密后写入,否则该字段在反序列化后为null或默认值 - 若字段未声明
transient,又不加密,就会以明文形式出现在字节流中——等于裸奔 - 推荐做法:敏感字段统一加
transient,强制自己在writeObject中显式加密写入,避免遗漏
重写 writeObject:三步写入法
方法签名必须严格为 private void writeObject(ObjectOutputStream out) throws IOException,JVM 才会识别并调用:
- 第一步:调用
out.defaultWriteObject()—— 序列化所有非transient、非static字段(不含已标记的敏感字段) - 第二步:对敏感字段加密,例如用 AES/GCM 生成密文 + IV;注意每次加密都应使用新 IV,并确保 IV 长度固定(如 12 字节)
- 第三步:把 IV 和密文一起写入流,顺序要和
readObject中读取顺序完全一致,例如:out.write(iv); out.writeInt(ciphertext.length); out.write(ciphertext);
配套实现 readObject:按序解密还原
没有对称的 readObject,加密就失去意义,且极易抛出 StreamCorruptedException 或字段错位:
- 先调用
in.defaultReadObject()恢复普通字段 - 再按写入顺序读取:先读 IV(如
byte[12]),再读密文长度,最后读指定长度的密文字节 - 用相同密钥和 IV 解密,结果赋值给对应
transient字段(如this.password = decrypt(iv, ciphertext);) - 密钥绝不能硬编码在类里,建议从系统属性、环境变量或安全配置中心加载
关键避坑提醒
这些细节不处理好,加密形同虚设:
-
writeObject和readObject必须都是private,不能是public或protected,也不能被子类继承覆盖 - 不要用 ECB 模式,优先选 AES/GCM(自带完整性校验)或 AES/CBC + 单独 HMAC
- IV 必须随密文一起序列化,但不能固定;解密时必须用写入时的那个 IV,否则失败
- 如果类有父类且父类含敏感字段,
defaultWriteObject()不会处理父类字段,需手动调用super.writeObject(out)(前提是父类也支持该机制)










