Java ObjectInputFilter 拒绝后怎么定位:serialClass、depth 与 arrayLength 测试清单
来源:17golang原创
时间:2026-08-16 21:15:45 257浏览 收藏
老系统把订单快照存成 Java 序列化字节,升级接口后,最麻烦的不是“能不能读出来”,而是输入里混进了不属于这个模块的类,或者数组和对象引用规模远超正常订单。把数据读进 ObjectInputStream 之前加一层 ObjectInputFilter,可以先按类名和资源上限做一次拦截。
- 白名单过滤优先允许业务 DTO 和必要的
java.base类型,其他类保持拒绝或未决,别只维护一份越来越长的黑名单。 FilterInfo能提供当前类、数组长度、对象图深度、引用数和输入字节数,类名检查与资源限制要同时做。createFilter的模式用分号分隔,maxarray、maxdepth等限制和类模式共同决定结果,顺序写错会让验收失真。- 过滤器是防御层,不等于可以放心读取不可信序列化数据;新接口优先选 JSON、协议缓冲等明确格式。
先理清楚:输入要过哪几道校验环节
把一次订单快照读取拆成三步更容易验证:先判断当前类是否属于允许集合,再判断数组和对象图是否超过正常业务规模,最后才让 ObjectInputStream 继续读取。过滤器检查的是反序列化过程中的对象信息,不会提前替你校验每个字段的业务合法性。

这里要特别注意边界:Oracle 官方文档明确说明,不可信数据的反序列化本身就存在风险。过滤器的价值是缩小可接受的类集合并限制对象图复杂度,不能把历史序列化格式变成一种天然安全的交换协议。
最小可用写法:只允许订单快照和基础类型
假设业务只保存 OrderSnapshot、OrderLine 和少量集合数据。先用模式过滤器限制包范围,再把输入流绑定到这个过滤器:
import java.io.ObjectInputFilter;
import java.io.ObjectInputStream;
import java.nio.file.Files;
import java.nio.file.Path;
Object readSnapshot(Path file) throws Exception {
var pattern = "com.example.order.**;java.base/*;maxarray=200;maxdepth=12;!*";
var filter = ObjectInputFilter.Config.createFilter(pattern);
try (var input = Files.newInputStream(file);
var objects = new ObjectInputStream(input)) {
objects.setObjectInputFilter(filter);
return objects.readObject();
}
}
java.base/* 让基础模块中的必要类型参与匹配,最后的 !* 把没有被前面模式覆盖的类直接拒绝掉。数组上限和深度上限不是可选配置:订单行数量异常、嵌套集合过深时,过滤器应当在读取过程中直接返回拒绝状态。
自定义检查:把“允许什么”和“最多多少”分开处理
预设模式字符串适合配置固定规则;如果还要记录具体的拒绝原因,可以自行实现一个轻量过滤器。返回 UNDECIDED 表示当前过滤器暂不做判定,返回 ALLOWED 或 REJECTED 才是明确的校验结论:
ObjectInputFilter orderFilter = info -> {
Class> type = info.serialClass();
if (info.arrayLength() > 200 || info.depth() > 12) {
return ObjectInputFilter.Status.REJECTED;
}
if (type == null) {
return ObjectInputFilter.Status.UNDECIDED;
}
if (type.getName().startsWith("com.example.order.")) {
return ObjectInputFilter.Status.ALLOWED;
}
if (type.getModule().getName().equals("java.base")) {
return ObjectInputFilter.Status.ALLOWED;
}
return ObjectInputFilter.Status.REJECTED;
};
数组检查不能只在 serialClass() 非空时执行,因为数组长度是过滤器单独提供的独立校验指标。对象图深度也应结合真实订单样本测出合理上限,直接套一个过小的通用数字,很可能把合法的嵌套 DTO 一起拦截掉。
防御盲区:黑名单为什么越补越难维护
黑名单的思路是“遇到一个危险类就加一条拒绝规则”,但业务依赖、库版本和类加载范围一变,很容易出现遗漏。白名单的边界更清晰:订单读取器只需要少数 DTO 和基础类型,未声明的类不应该因为“暂时没发现问题”就自动放行。
如果多个模块各自设置流级过滤器,还要核查 JVM 级过滤器和过滤器工厂的合并关系。Oracle 的过滤文档强调,组合过滤器遇到任一明确拒绝时应直接返回拒绝结果;不能在局部过滤器里简单返回新规则,反而绕开全局安全边界。

用四组样本做验证,不要测一次正常就上线
| 测试样本 | 预期结果 | 核对要点 |
|---|---|---|
| 正常 OrderSnapshot 实例 | 允许读取 | 业务包名、数组长度、深度都在预设范围内 |
| 未登记的业务类 | 拒绝读取 | 日志能直接定位到对应 serialClass |
| 超长 OrderLine 数组 | 拒绝读取 | arrayLength 超过预设的 maxarray 阈值 |
| 多层嵌套快照 | 拒绝读取 | depth 超过预设的 maxdepth 阈值,业务侧保留完整失败记录 |
每组样本都要记录过滤器配置、运行的 Java 版本、结果状态和具体失败原因。不要只断言“抛出了异常”,还要确认是输入类不允许、数组超限还是深度超限,否则后续规则调整后很难知道到底放宽了哪一道校验。
上线前的安全核对清单
- 能修改协议就停止新增 Java 原生序列化入口,迁移到字段和版本都更明确的数据格式。
- 必须兼容旧数据时,先盘点每个读取点的 DTO 白名单,再设置数组、深度、引用数和字节数上限。
- 把过滤器拒绝日志接入告警机制,但不要把完整输入内容和敏感订单字段直接写进日志。
- 升级 JDK、引入新 DTO 或新增集合字段后,重新跑一遍四组边界样本校验。
相关问题
ObjectInputFilter 能让不可信序列化数据变安全吗?
不能。它是类和资源边界的防御控制,不能替代避免读取不可信数据、认证来源和迁移到更明确数据格式等措施。
ALLOWED 和 UNDECIDED 有什么区别?
ALLOWED 是当前过滤器明确放行,UNDECIDED 是当前过滤器不表态,组合过滤器或后续规则仍可能给出拒绝结果。
只设置 maxdepth 够不够?
通常不够。对象图深度、引用数、数组长度和输入字节数限制关注的是不同资源维度,应根据正常业务样本组合设置并用边界数据验证。
过滤器应该设置在全局还是单个流上?
全局规则适合统一安全底线,单个流适合配置更严格的业务白名单。多层规则并存时要确认组合逻辑没有绕开全局过滤器。
把过滤器当成协议边界来维护
ObjectInputFilter 最有用的地方,不是帮旧序列化代码“加一行安全配置”,而是把可读类集合、对象图规模和验收样本都明确固化下来。先收紧输入边界,再逐步迁移掉不必要的原生序列化,才是更稳妥的长期方案。可继续参考 OpenJDK JEP 290、Oracle ObjectInputFilter API 和 Oracle Serialization Filtering 指南。
-
487 收藏
-
313 收藏
-
196 收藏
-
306 收藏
-
393 收藏
-
文章 · java教程 | 3小时前 | 反序列化 · Java教程 · 安全编程 · Java IO · java Java安全 ObjectInputFilter 反序列化过滤 Serialization Filter186 收藏
-
文章 · java教程 | 5小时前 | 密码学 · Java教程 · Java 25 · HKDF · 密钥派生 · Java 25 KDF Key Derivation Function API HKDF JEP 510 密钥派生147 收藏
-
143 收藏
-
270 收藏
-
文章 · java教程 | 6小时前 | Java教程 · Java 24 · 字节码 · Class-File API · JVM工具 · 字节码 Java 24 Class-File API ClassModel ASM替代 java.lang.classfile352 收藏
-
428 收藏
-
文章 · java教程 | 8小时前 | 并发编程 · Java教程 · 虚拟线程 · threadlocal 请求上下文 Java 25 StructuredTaskScope ScopedValue391 收藏
-
296 收藏
-
文章 · java教程 | 1星期前 | Stream · Java教程 · 性能边界 · mapMulti · flatMap · Java mapMulti Stream flatMap Java Stream 条件展开 Java 16250 收藏
-
150 收藏
-
125 收藏
-
242 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习