java自9起引入objectinputfilter白名单机制防范反序列化风险,推荐用config.createfilter设置严格类匹配规则,支持jvm参数全局兜底,需注意内部类命名、第三方库显式授权及禁用enableresolveobject。

Java 中 ObjectInputStream 默认允许反序列化任意类,存在严重安全风险(如远程代码执行)。自 Java 9 起引入了 ObjectInputFilter 机制,Java 17 进一步强化为默认启用的白名单控制。实现“只读反序列化白名单”核心是设置严格、可维护的类过滤器。
使用 ObjectInputFilter 设置白名单
从 Java 9 开始,可通过 ObjectInputStream.setObjectInputFilter() 设置过滤器。推荐在构造后立即设置,避免被绕过:
- 过滤器必须在调用
readObject()前设置,且不可更改 - 推荐使用静态工厂方法
ObjectInputFilter.Config.createFilter(String pattern)构建白名单规则 - 模式语法支持
maxdepth、maxarray、maxrefs等限制,但白名单关键靠module/classname匹配
示例:只允许反序列化 java.lang.String 和自定义包下的类:
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
"java.lang.String;com.example.model.*;maxdepth=5;maxarray=10000"));
自定义 ObjectInputFilter 实现精细控制
当内置模式语法无法满足需求(如需运行时校验、日志审计、动态白名单),可实现 ObjectInputFilter 接口:
-
checkInput(FilterInfo info)返回ALLOWED、REJECTED或UNDECIDED -
info.serialClass()获取待反序列化的类,可结合类名、包名、是否为 record、是否含危险方法等判断 - 建议缓存已验证类,避免重复反射开销;对
null类或未授权类直接返回REJECTED
示例片段:
ObjectInputFilter filter = info -> {
Class> clazz = info.serialClass();
if (clazz == null) return ObjectInputFilter.Status.REJECTED;
String name = clazz.getName();
if (name.startsWith("java.lang.") ||
name.startsWith("com.example.dto.")) {
return ObjectInputFilter.Status.ALLOWED;
}
return ObjectInputFilter.Status.REJECTED;
};
ois.setObjectInputFilter(filter);
全局默认过滤器与 JVM 参数配合
除单个流设置外,还可通过 JVM 启动参数统一管控:
-
-Djdk.serialFilter="java.lang.String;com.example.**"设置全局默认过滤器 - 该参数会被
ObjectInputStream在无显式 filter 时自动加载 - 若代码中调用
setObjectInputFilter(null),将回退到该全局策略(Java 17+) - 生产环境强烈建议配置此参数作为兜底,避免遗漏
注意事项与常见陷阱
白名单看似简单,实际易踩坑:
- 注意内部类命名(如
com.example.Outer$Inner),白名单需显式包含$符号或使用** - 泛型类型擦除不影响类名匹配,但需确保反序列化目标类本身在白名单中
- 第三方库类(如 Jackson、Apache Commons)若参与反序列化,必须显式加入白名单
- 禁用
enableResolveObject(),防止绕过 filter 的恶意重写逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











