怎么给 Java 的反序列化加一道类型边界?这篇只做防御侧的验证:用 ObjectInputFilter 的白名单、黑名单和资源限制,看哪些对象被拒绝、错误是什么、配置在哪一层生效(序列化的字节结构见前面的篇目;不包含任何攻击载荷)。
不设过滤器:Ok → 成功:Ok;Other → 成功:Other 白名单过滤器 "Main$Ok;java.lang.*;java.util.ArrayList;!*":Ok → 成功:Ok;Other → InvalidClassException: filter status: REJECTED;ArrayList(含 String)→ 成功:ArrayList 黑名单过滤器 "!Main$Other":Other → InvalidClassException: filter status: REJECTED;Ok → 成功:Ok(黑名单之外的类默认放行) 同样的黑名单过滤器,在 JDK 的默认状态(UNDECIDED)下对 ArrayList → 成功:ArrayList
maxdepth=50 嵌套 200 层的数组 → InvalidClassException: filter status: REJECTED maxdepth=50 10 万个 int 的数组 → 成功:int[] maxdepth=50 含 500 个元素的列表 → 成功:CopiesList maxarray=1000 嵌套 200 层的数组 → 成功:Object[] maxarray=1000 10 万个 int 的数组 → InvalidClassException: filter status: REJECTED maxarray=1000 含 500 个元素的列表 → 成功:CopiesList maxrefs=100 嵌套 200 层的数组 → InvalidClassException: filter status: REJECTED maxrefs=100 10 万个 int 的数组 → 成功:int[] maxrefs=100 含 500 个元素的列表 → InvalidClassException: filter status: REJECTED maxbytes=1000 嵌套 200 层的数组 → InvalidClassException: filter status: REJECTED maxbytes=1000 10 万个 int 的数组 → 成功:int[] maxbytes=1000 含 500 个元素的列表 → InvalidClassException: filter status: REJECTED 不设限制时这三个都能读:成功:Object[] | 成功:int[] | 成功:CopiesList
设了进程级过滤器 ObjectInputFilter.Config.setSerialFilter("Main$Ok;java.lang.*;!*") 之后,没有给流单独设置过滤器:Ok → 成功:Ok;Other → InvalidClassException: filter status: REJECTED
给某个流单独设了过滤器 "Main$Other;!*":Other → 成功:Other;Ok → InvalidClassException: filter status: REJECTED(流上的过滤器取代进程级的)
第二次 setSerialFilter → IllegalStateException: Serial filter can only be set once
自己写的过滤器(lambda 按类名前缀):Ok → 成功:Ok;ArrayList → InvalidClassException: filter status: REJECTED
ObjectInputFilter.merge(限制深度 3, 白名单):Ok → 成功:Ok
rejectUndecidedClass 包装的白名单:InvalidClassException: filter status: REJECTED(只有一个允许项、没有 !* 时,不在清单里的类默认是 UNDECIDED,用它转成拒绝)