Java反序列化防护需重写ObjectInputStream的resolveClass()拦截黑名单类,resolveProxyClass()控制代理接口,resolveObject()替换危险对象;优先用JSON等非序列化格式,JDK9+推荐JEP 290过滤器。

在 Java 反序列化过程中,通过自定义 ObjectInputStream 拦截并替换敏感类(如 java.util.LinkedHashSet、org.apache.commons.collections4.set.TreeSet 等可能被用于反序列化链的类),核心是重写 resolveClass() 方法,在类加载前做白名单校验或强制替换为安全类型。
重写 resolveClass() 实现类名过滤
这是最常用且有效的拦截方式。JVM 在反序列化时会调用该方法将 ObjectStreamClass 转为 Class,此时可检查类名并抛出异常或返回替代类:
- 继承
ObjectInputStream,在构造时调用super(inputStream) - 覆写
resolveClass(ObjectStreamClass desc) - 提取类名:
desc.getName(),判断是否在黑名单中(如"com.sun.rowset.JdbcRowSetImpl"、"org.springframework.core.io.FileSystemResource") - 匹配则抛出
InvalidClassException,阻止后续反序列化流程
示例片段:
public class SecureObjectInputStream extends ObjectInputStream {
private static final Set<String> BLOCKED_CLASSES = Set.of(
"com.sun.rowset.JdbcRowSetImpl",
"org.apache.commons.collections.functors.InvokerTransformer"
);
public SecureObjectInputStream(InputStream in) throws IOException {
super(in);
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String name = desc.getName();
if (BLOCKED_CLASSES.contains(name)) {
throw new InvalidClassException("Blocked class: " + name);
}
return super.resolveClass(desc);
}
}
用 resolveProxyClass() 控制动态代理类加载
若反序列化流中含动态代理对象(如 java.lang.reflect.Proxy 实例),JVM 会调用 resolveProxyClass()。不拦截会导致恶意接口+InvocationHandler 绕过类名检查:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 覆写该方法,检查
interfaceNames数组内容 - 禁止加载危险接口(如
javax.management.ObjectName、自定义攻击接口) - 可统一返回
Proxy.getProxyClass(...)的安全空实现,或直接抛异常
配合 enableResolveObject() 实现运行时对象替换(慎用)
调用 enableResolveObject(true) 后,每次反序列化完一个对象都会触发 resolveObject()。可用于将高危实例替换成空壳或包装器:
- 仅对已知安全类型(如
String、Integer)放行 - 对
LinkedHashSet等集合类,可将其内容复制到HashSet并返回新实例(需注意递归处理) - 注意:该方法影响所有对象,性能开销大;且若原始对象含 final 字段或不可变结构,替换后可能破坏逻辑
补充防御建议
单靠自定义 ObjectInputStream 不足以完全免疫反序列化风险:
- 优先使用 JSON/YAML/Protobuf 等非原生序列化格式,避免
Serializable机制 - 若必须用 Java 序列化,确保输入流来源可信(如内网 RPC、本地文件),不暴露给外部请求
- 升级 JDK:JEP 290(Java 9+)引入了
ObjectInputFilter,支持更细粒度的类/数组/深度/引用限制,比手动重写更可靠 - 运行时可配置过滤器:
System.setProperty("jdk.serialFilter", "maxarray=100000;maxdepth=10;maxrefs=1000;!*;java.lang.*;java.util.*;")

















