Java中SecurityManager无法限制反序列化危险类,因其不参与类加载校验且绕过权限检查;真正有效的是JDK9+的ObjectInputFilter白名单机制及替代序列化协议。

Java 中不能通过 SecurityManager 限制危险类的反序列化。
这个做法在技术上是无效的,原因很明确:SecurityManager 不参与反序列化过程中的类加载校验,也不检查待反序列化的类型是否危险。
它只在代码显式调用敏感 API(如 new FileInputStream()、System.exit())时进行运行时权限拦截,而反序列化中 ObjectInputStream 加载类的行为绕过了 SecurityManager 的常规检查路径。
为什么 SerializablePermission 和 SecurityManager 对反序列化无效?
-
SerializablePermission("enableSerialization")只控制谁能调用ObjectOutputStream.writeObject(),不干预反序列化; -
SecurityManager的checkPermission()方法不会在resolveClass()或readObject()执行时自动触发; - 即使你重写了
SecurityManager.checkPackageAccess(),也无法阻止ObjectInputStream内部通过ClassLoader.loadClass()加载恶意类; - Java 9 之前没有机制在反序列化前拦截类名,JDK 默认完全信任输入流;
-
从 Java 17 开始,
SecurityManager已被正式移除,所有基于它的防护方案已不可用。
真正有效的替代方案:ObjectInputFilter(JDK 9+)
必须使用 ObjectInputFilter 在反序列化开始前绑定白名单或限制策略:
- ✅ 支持按类名、包名通配(如
com.example.model.**); - ✅ 可设深度(
maxdepth=5)、引用数(maxrefs=100)、数组大小(maxarray=10000); - ✅ 拒绝未匹配项(末尾加
!表示兜底拒绝); - ✅ 可全局设置(
-Djdk.serialFilter=...),也可 per-stream 设置(推荐)。
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(ObjectInputFilter.Config.createFilter(
"java.lang.String;java.util.ArrayList;com.myapp.dto.**;maxdepth=4;maxrefs=50;!"
));
Object obj = ois.readObject(); // 此时才真正执行反序列化⚠️ 注意:
setObjectInputFilter()必须在readObject()之前调用,否则无效。立即学习“Java免费学习笔记(深入)”;
额外加固手段(不依赖 SecurityManager)
-
声明敏感字段为
transient:如密码、token、连接池句柄等,JVM 自动跳过; -
重写
private void readObject(ObjectInputStream in):反序列化后立即清空或重置高危字段; -
自定义
ObjectInputStream子类 +resolveClass()校验:运行时白名单比对,拒绝非法类名; -
禁用
ObjectInputStream的默认行为:改用 JSON(Jackson/Gson)、Protobuf、Avro 等更安全的序列化协议; -
启动参数强制过滤(生产环境建议):
-Djdk.serialFilter="maxdepth=3;maxrefs=20;maxarray=5000;java.base/*;java.desktop/*;!"
不复杂但容易忽略:反序列化安全的关键,从来不是“谁能序列化”,而是“谁的数据能被还原成什么类”。别再尝试用已淘汰的 SecurityManager 做反序列化防护了。

















