Java反序列化漏洞本质是信任不可信字节流,需分层防护:优先启用ObjectInputFilter白名单(Java 9+),精确指定类名;辅以JVM参数兜底、禁用危险行为、重写readObject校验字段;根本方案是停用原生序列化,改用JSON、Protobuf等安全格式。

Java 反序列化漏洞本质是“信任了不可信的字节流”,导致恶意类被加载、危险方法被自动调用。避免攻击不能只靠某一个补丁,而要分层设防:从源头禁用、运行时拦截、逻辑加固到格式替代,环环相扣。
启用 ObjectInputFilter 白名单(Java 9+ 推荐首选)
这是目前最轻量、最可靠的运行时防护机制,它在反序列化开始前就完成类名校验,不依赖开发者手动检查字段或逻辑。
- 必须在创建 ObjectInputStream 实例后、调用 readObject() 前设置过滤器
- 白名单规则应精确到具体类,例如:java.util.ArrayList;com.myapp.User;com.myapp.Order,避免使用宽泛通配符如 com.myapp.*
- 可配合 JVM 参数全局兜底:-Djdk.serialFilter="maxdepth=10;maxarray=100000;deny=org.apache.commons.collections.*",但生产环境仍建议代码中显式配置,防止参数遗漏
禁用危险行为与高危类(双重拦截)
即使类在白名单中,其 readObject()、静态块或 finalize() 仍可能执行命令。需从 JVM 层面封堵执行通道:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 若仍在用 Java 8 或 SecurityManager 未被移除的版本,可通过自定义 SecurityManager 拦截 Runtime.exec、ProcessBuilder.start 等系统调用
- Java 17+ 已默认移除 SecurityManager,此时可用字节码插桩(如 Byte Buddy)或 JVM Agent 在关键方法入口注入检查逻辑
- 对已知利用链中的高危类(如 javax.management.BadAttributeValueExpException、org.apache.commons.collections.Transformer)直接加入过滤器黑名单,形成白+黑双控
重写 readObject 做字段级校验(仅限必须保留原生序列化的场景)
当业务强依赖 Java 原生序列化(如遗留 RPC 协议),可在关键类中重写私有 readObject 方法,在字段赋值后插入校验逻辑:
立即学习“Java免费学习笔记(深入)”;
- 方法签名必须严格为:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- 校验代码必须放在 in.defaultReadObject() 之后,确保字段已完成反序列化
- 敏感字段建议声明为 transient,改由 readObject 中手动读取并校验(如 in.readInt()),防止绕过
- 单例类应补充 readResolve() 方法,返回唯一实例,防止反序列化伪造新对象
根本性规避:停用原生序列化,改用安全格式
白名单和校验仍是“加固一扇门”,而换格式是“拆掉那扇门”。只要业务不强依赖 Java 对象图还原,就应主动迁移:
- Web/REST 场景优先用 JSON(Jackson / Gson):天然不执行代码、不还原类结构,只解析为 Map 或 DTO;务必关闭 enableDefaultTyping(),禁用自动类型推断
- RPC 场景推荐 gRPC + Protobuf:协议严格定义 schema,无反射、无动态类加载,传输内容完全可控
- 若必须保留二进制交互,可考虑 Kryo(开启 RegistrationRequired 模式)或 FST,但需自行维护注册表并定期审计

















