Java反序列化校验核心是readObject方法与ObjectInputValidation接口协同:先调用defaultReadObject还原字段,再校验状态;validateObject用于对象图完整性检查;需配合transient字段、readResolve及禁用原生反序列化等防御措施。

Java 反序列化时校验对象合法性,核心是利用 readObject 方法和 ObjectInputValidation 接口,在字段还原后、对象交付前主动检查状态。这不是事后补救,而是把校验嵌入反序列化流程的关键环节。
在 readObject 中校验:先还原再检查
必须重写 private void readObject(ObjectInputStream in),且严格按顺序执行:
- 第一行调用
in.defaultReadObject()—— 否则所有非transient字段仍为默认值(null、0、false),校验无意义 - 紧接着写校验逻辑:比如
if (age < 0 || age > 150) throw new InvalidObjectException("invalid age"); - 可覆盖范围约束(金额、状态码)、非空判断(
username == null)、格式校验(邮箱正则)、逻辑一致性(startTime.after(endTime))等 - 校验失败时抛出
InvalidObjectException,JVM 会立即终止反序列化并丢弃该对象
用 ObjectInputValidation 做完整性兜底
当需要检查对象图整体状态(如关联对象是否完整、集合元素是否合法),适合用 ObjectInputValidation:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 类实现该接口,并重写
validateObject()方法 - 在
readObject中调用in.registerValidation(this, 0)注册校验器(优先级数字越小越早执行) -
validateObject()在整个对象图构建完毕后触发,此时可安全访问所有已反序列化的字段和引用对象 - 同样用
InvalidObjectException表示校验不通过
配合其他机制防绕过
单靠校验逻辑不够,需组合防御:
立即学习“Java免费学习笔记(深入)”;
- 敏感字段(如密码、token)声明为
transient,在readObject中手动读取并校验,避免被字节流直接篡改 - 单例类补充
private Object readResolve(),返回唯一实例,防止反序列化伪造新对象 - 避免在
readObject或validateObject中调用普通 getter/setter 或外部服务(如数据库、HTTP),以防子类覆写或引入副作用
注意根本性风险
这些校验能提升数据质量,但无法解决原生序列化的底层缺陷:
- 无法拦截 gadget chain 类攻击(如 CommonsCollections 链)
- 不能替代输入过滤或白名单机制
- 生产环境应优先禁用
ObjectInputStream.readObject(),改用 JSON、Protobuf 等更可控的序列化方案

















