白名单机制是最可靠防御方式,需在resolveclass阶段通过desc.getname()精确匹配预定义安全类名,禁用通配和正则,统一入口封装并配合objectinputfilter等纵深防护措施。

Java 反序列化通过白名单机制限制可加载类,核心是在类真正加载前拦截并校验类名——只放行预定义的、业务必需且确认安全的类,其余一律拒绝。这是目前最可靠、最推荐的防御方式。
白名单必须在 resolveClass 阶段生效
ObjectInputStream 在反序列化时,会在 resolveClass() 方法中根据类描述符(ObjectStreamClass)加载对应类。这个时机早于 readObject() 执行,也早于任何静态块或构造器触发。因此,白名单校验必须重写该方法,从 desc.getName() 获取原始类名进行匹配,不能依赖 try-catch 或后续逻辑拦截。
- 错误做法:在 readObject() 后检查对象类型——此时恶意类可能已执行静态初始化代码
- 错误做法:用 Class.forName() 主动加载再判断——会提前触发类加载和危险行为
- 正确做法:直接比对 desc.getName() 是否在允许集合中,不解析、不加载、不实例化
类名匹配要精确且可控
白名单应以具体类名为主,包路径通配为辅,并严格限定范围。避免使用 java.**、javax.**、org.apache.commons.** 等高危前缀,更不能开放 * 通配。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 推荐方式:显式列出关键 DTO 和基础类型,如 "java.lang.String"、"com.example.order.OrderDetail"
- 谨慎使用:包路径前缀匹配,如 className.startsWith("com.example.dto.")
- 禁用方式:正则表达式匹配(易被绕过)、模糊匹配(如 contains("dto"))
统一入口封装 + 全局强制使用
所有反序列化调用都必须经过同一个安全入口,例如自定义的 SafeObjectInputStream。不能让开发人员随意 new ObjectInputStream,否则白名单形同虚设。
- 将白名单集合设为 final static,集中管理、禁止运行时修改
- 在构造函数中调用 enableResolveObject(true),确保 resolveClass 被调用
- 配合 JDK 9+ 的 ObjectInputFilter 做双重防护(如限制 maxdepth=5、maxrefs=1000)
配套措施不可少
白名单不是孤立策略,需结合其他加固手段形成纵深防御:
- 禁用原生序列化协议:优先改用 JSON、Protobuf、Jackson 等不支持任意类加载的格式
- 校验 Serializable 实现:确保业务类确实实现了 Serializable,且不含危险字段(如 Runtime、ProcessBuilder)
- 记录并告警:对每次白名单拒绝行为打日志,包含类名、来源 IP、时间戳,便于溯源分析
- 定期审计更新:随着业务迭代,及时增删白名单项,避免过度放行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










