JEP 290 深入解析与教学文档
1. JEP 290 概述
JEP 290(JDK Enhancement Proposal 290)是Java平台提供的一个安全增强功能,全称为"Filter Incoming Serialization Data"(过滤传入的序列化数据)。其主要目的是为Java反序列化操作提供安全防护机制。
1.1 主要功能
- 类过滤机制:提供黑白名单方式限制可反序列化的类
- 图形复杂度控制:限制反序列化深度和复杂度
- RMI验证机制:为RMI导出的对象设置验证机制
- 全局配置:支持通过属性或配置文件配置全局过滤器
1.2 支持版本
- JDK 9 原生支持
- 向后移植到:
- JDK 8u121
- JDK 7u131
- JDK 6u141
2. 核心类与架构
2.1 核心类结构
ObjectInputStream
├── serialFilter (ObjectInputFilter)
│ ├── checkInput() 方法
│ ├── Config (静态类)
│ │ ├── configuredFilter
│ │ ├── serialFilter
│ │ ├── createFilter()
│ │ └── getSerialFilter()
│ └── Global (静态类,Config的内部类)
│ ├── filters (函数列表)
│ └── checkInput() 方法
└── filterCheck() 方法
2.2 ObjectInputStream 类
JEP 290 在 ObjectInputStream 中增加了两个关键部分:
- serialFilter 属性:
ObjectInputFilter类型,实际过滤器实现 - filterCheck 方法:执行过滤检查逻辑
构造函数行为:
- 两个构造函数都会将
serialFilter初始化为ObjectInputFilter.Config.getSerialFilter()
filterCheck 方法逻辑:
- 检查
serialFilter是否为空 - 封装检查信息为
FilterValues对象 - 调用
serialFilter.checkInput()进行检查 - 根据返回状态决定是否抛出异常
2.3 ObjectInputFilter 接口
函数式接口,核心方法是 checkInput(),包含以下组件:
- Config 静态类:管理全局过滤器配置
- FilterInfo 接口:提供过滤检查的上下文信息
- Status 枚举:表示过滤结果状态(ALLOWED, REJECTED, UNDECIDED)
2.4 Config 静态类
关键字段与方法:
-
configuredFilter:静态字段,初始化时从以下位置读取配置:
- JVM 参数
jdk.serialFilter - 配置文件
%JAVA_HOME%/conf/security/java.security
- JVM 参数
-
createFilter():将规则字符串解析为
Global对象 -
serialFilter:静态字段,初始化为
configuredFilter的值 -
getSerialFilter():返回
serialFilter字段值
2.5 Global 静态类
实现 ObjectInputFilter 接口,关键特性:
- filters 字段:函数列表,存储解析后的过滤规则
- checkInput() 方法:遍历 filters 执行检查
- 构造函数:解析 JEP 290 规则字符串为 lambda 表达式
JEP 290 规则格式:
pattern=setting[,pattern=setting...]
其中 pattern 支持:
- 完整类名
- 包名后跟 ".*"
- 模块名后跟 "/"
- 通配符 "**"
3. 过滤器类型与配置
3.1 全局过滤器
通过设置 Config.serialFilter 静态字段实现,影响所有 ObjectInputStream 实例。
配置方式:
- JVM 参数:
-Djdk.serialFilter=规则字符串 - 配置文件:在
java.security中添加jdk.serialFilter=规则字符串
WebLogic 示例:
WebLogic 启动时会设置全局过滤器:
- 创建
WebLogicObjectInputFilterWrapper对象 - 通过反射设置
Config.serialFilter - 包含 WebLogic 的黑名单规则
3.2 局部过滤器
针对单个 ObjectInputStream 实例的过滤设置。
设置方式:
- 直接调用:
- JDK 9+:
setObjectInputFilter() - JDK 8u121-8u201:
setInternalObjectInputFilter()
- JDK 9+:
- 通过
Config.setObjectInputFilter()设置
4. RMI 中的 JEP 290 实现
4.1 RegistryImpl 的特殊处理
-
Target 对象特征:
- ID 固定为 0 (
ObjID.REGISTRY_ID) - disp 的 filter 为
RegistryImpl::registryFilter - skel 为
RegistryImpl_skel
- ID 固定为 0 (
-
过滤器初始化:
- 从
sun.rmi.registry.registryFilter读取规则 - 默认白名单包含 RMI 相关类
- 从
-
请求处理流程:
- 在
unmarshalCustomCallData中设置局部过滤器 - 先检查自定义规则,再检查默认白名单
- 在
4.2 DGCImpl 的特殊处理
-
Target 对象特征:
- ID 固定为 2 (
ObjID.DGC_ID) - disp 的 filter 为
DGCImpl::DGCFilter - skel 为
DGCImpl_skel
- ID 固定为 2 (
-
过滤器初始化:
- 从
sun.rmi.transport.dgcFilter读取规则 - 默认白名单包含 DGC 相关类
- 从
5. 绕过与防御
5.1 绕过 JEP 290 的条件
当服务端导出以下对象时可能绕过防护:
- 普通远程对象(非 RegistryImpl/DGCImpl)
- 对象方法参数类型为 Object
- Target 对象的 disp.filter 为 null
原因:缺少局部过滤器设置,全局过滤器可能被绕过
5.2 反制措施
恶意服务端可反制攻击客户端:
- 针对
RegistryImpl_Stub.lookup/list:直接返回恶意对象 - 针对枚举工具(如 RmiTaste):利用客户端自动反序列化特性
6. 最佳实践
-
全局配置:
- 在生产环境中配置
jdk.serialFilter - 使用严格的白名单策略
- 在生产环境中配置
-
RMI 安全:
- 为自定义远程对象设置过滤器
- 限制可绑定的对象类型
-
防御绕过:
- 监控和限制 Object 类型参数的方法
- 定期更新黑名单规则
-
版本管理:
- 使用已包含 JEP 290 的 JDK 版本
- 及时应用安全补丁
7. 总结
JEP 290 通过多层次的过滤机制增强了 Java 反序列化的安全性:
- 全局与局部过滤器相结合
- RMI 核心组件内置防护
- 灵活的规则配置方式
- 图形复杂度控制
正确理解和配置 JEP 290 是防御反序列化攻击的关键,但也需要注意其局限性,结合其他安全措施构建纵深防御体系。