JDK解决反序列化的方法
字数 1407 2025-08-27 12:33:42

Java反序列化漏洞与JDK解决方案详解

一、Java反序列化漏洞背景

Java反序列化漏洞是近年来安全领域的热点问题,几乎所有使用原生Java序列化的框架都可能受到反序列化攻击。Java序列化是Java内置功能,可以将对象转换为二进制数据(序列化),也能将二进制数据还原为对象(反序列化)。

主要应用场景

  • JMS消息队列系统:通过序列化传输对象数据
  • RESTful客户端:序列化存储OAuth token等对象
  • Java远程方法调用(JMI):JVM间使用序列化通信

二、反序列化漏洞原理

反序列化过程

当应用代码触发反序列化时,ObjectInputStream将流数据初始化为对象。它会:

  1. 匹配字节流与JVM类路径中的类
  2. 根据流中的魔术字节识别对象类型
  3. 无法解析的类型会被视为TC_OBJECT类型

漏洞成因

攻击者可构造特殊的字节流,利用JVM类路径中存在的特定类,通过已知利用链实现远程命令执行(RCE)。著名的工具如ysoserial可以生成此类攻击payload。

三、传统缓解方案

1. LookAheadObjectInputStream策略

通过继承ObjectInputStream并重写resolveClass()方法,验证类是否可加载。

实现方式

  • 白名单:只允许特定类被反序列化
  • 黑名单:阻止已知有问题的类
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
    String name = desc.getName();
    if(isBlacklisted(name)) {
        throw new SecurityException("Deserialization is blocked for security reasons");
    }
    if(isWhitelisted(name)) {
        throw new SecurityException("Deserialization is blocked for security reasons");
    }
    return super.resolveClass(desc);
}

优缺点

  • 白名单:更安全,但需要维护允许的类列表
  • 黑名单:易被绕过,需要持续更新

四、JDK新解决方案:序列化过滤(JEP 290)

Oracle在JDK 9中引入了serialization filtering机制,后被移植到旧版JDK。

核心接口:ObjectInputFilter

提供配置能力,在反序列化时验证输入数据。返回状态:

  • Status.ALLOWED:允许
  • Status.REJECTED:拒绝
  • Status.UNDECIDED:未决定

可访问的信息

  • arrayLength:数组长度
  • depth:对象深度
  • references:对象引用数
  • streamBytes:流占用空间大小

五、过滤器配置方式

1. 自定义过滤器(Custom Filter)

适用于特定反序列化场景,实现ObjectInputFilter接口并重写checkInput方法。

static class VehicleFilter implements ObjectInputFilter {
    final Class<?> clazz = Vehicle.class;
    final long arrayLength = -1L;
    final long totalObjectRefs = 1L;
    final long depth = 1l;
    final long streamBytes = 95L;
    
    public Status checkInput(FilterInfo filterInfo) {
        if (filterInfo.arrayLength() < this.arrayLength || 
            filterInfo.arrayLength() > this.arrayLength ||
            filterInfo.references() < this.totalObjectRefs || 
            filterInfo.references() > this.totalObjectRefs ||
            filterInfo.depth() < this.depth || 
            filterInfo.depth() > this.depth ||
            filterInfo.streamBytes() < this.streamBytes || 
            filterInfo.streamBytes() > this.streamBytes) {
            return Status.REJECTED;
        }
        if (filterInfo.serialClass() == null) {
            return Status.UNDECIDED;
        }
        if (filterInfo.serialClass() != null && filterInfo.serialClass() == this.clazz) {
            return Status.ALLOWED;
        } else {
            return Status.REJECTED;
        }
    }
}

2. 全局过滤器(Process-wide Filter)

通过jdk.serialFilter配置,可作为系统属性或安全属性。

过滤规则示例

  • 限制参数:

    maxdepth=value  // 最大图深度
    maxrefs=value   // 最大内部引用数
    maxbytes=value  // 输入流最大字节数
    maxarray=value  // 最大数组大小
    
  • 类名匹配:

    "jdk.serialFilter=org.example.Vehicle;!*"  // 只允许特定类
    "jdk.serialFilter=org.example.**"         // 允许包及子包所有类
    "jdk.serialFilter=org.example.*"          // 只允许包内类
    "jdk.serialFilter=*;!org.example.**"      // 拒绝特定包
    

3. 内置过滤器(Built-in Filters)

主要用于RMI和分布式垃圾回收(DGC)。

RMI Registry白名单

java.lang.Number
java.rmi.Remote
java.lang.reflect.Proxy
sun.rmi.server.UnicastRef
sun.rmi.server.RMIClientSocketFactory
sun.rmi.server.RMIServerSocketFactory
java.rmi.activation.ActivationID
java.rmi.server.UID

DGC白名单

java.rmi.server.ObjID
java.rmi.server.UID
java.rmi.dgc.VMID
java.rmi.dgc.Lease

可通过sun.rmi.registry.registryFiltersun.rmi.transport.dgcFilter添加自定义过滤器。

六、总结

Java反序列化本身不是漏洞,问题在于反序列化不受信任的数据。JEP 290引入的过滤机制为开发者提供了标准化的解决方案:

  1. 支持自定义过滤器满足特定场景需求
  2. 提供全局过滤器配置简化部署
  3. 内置RMI和DGC的安全过滤器
  4. 细粒度的过滤控制(类名、大小、深度等)

开发者应根据实际需求选择合适的过滤策略,优先考虑白名单方式,并结合JDK提供的过滤机制,有效缓解反序列化攻击风险。

Java反序列化漏洞与JDK解决方案详解 一、Java反序列化漏洞背景 Java反序列化漏洞是近年来安全领域的热点问题,几乎所有使用原生Java序列化的框架都可能受到反序列化攻击。Java序列化是Java内置功能,可以将对象转换为二进制数据(序列化),也能将二进制数据还原为对象(反序列化)。 主要应用场景 JMS消息队列系统 :通过序列化传输对象数据 RESTful客户端 :序列化存储OAuth token等对象 Java远程方法调用(JMI) :JVM间使用序列化通信 二、反序列化漏洞原理 反序列化过程 当应用代码触发反序列化时, ObjectInputStream 将流数据初始化为对象。它会: 匹配字节流与JVM类路径中的类 根据流中的魔术字节识别对象类型 无法解析的类型会被视为 TC_OBJECT 类型 漏洞成因 攻击者可构造特殊的字节流,利用JVM类路径中存在的特定类,通过已知利用链实现远程命令执行(RCE)。著名的工具如 ysoserial 可以生成此类攻击payload。 三、传统缓解方案 1. LookAheadObjectInputStream策略 通过继承 ObjectInputStream 并重写 resolveClass() 方法,验证类是否可加载。 实现方式 白名单 :只允许特定类被反序列化 黑名单 :阻止已知有问题的类 优缺点 白名单 :更安全,但需要维护允许的类列表 黑名单 :易被绕过,需要持续更新 四、JDK新解决方案:序列化过滤(JEP 290) Oracle在JDK 9中引入了 serialization filtering 机制,后被移植到旧版JDK。 核心接口:ObjectInputFilter 提供配置能力,在反序列化时验证输入数据。返回状态: Status.ALLOWED :允许 Status.REJECTED :拒绝 Status.UNDECIDED :未决定 可访问的信息 arrayLength :数组长度 depth :对象深度 references :对象引用数 streamBytes :流占用空间大小 五、过滤器配置方式 1. 自定义过滤器(Custom Filter) 适用于特定反序列化场景,实现 ObjectInputFilter 接口并重写 checkInput 方法。 2. 全局过滤器(Process-wide Filter) 通过 jdk.serialFilter 配置,可作为系统属性或安全属性。 过滤规则示例 限制参数: 类名匹配: 3. 内置过滤器(Built-in Filters) 主要用于RMI和分布式垃圾回收(DGC)。 RMI Registry白名单 DGC白名单 可通过 sun.rmi.registry.registryFilter 和 sun.rmi.transport.dgcFilter 添加自定义过滤器。 六、总结 Java反序列化本身不是漏洞,问题在于反序列化不受信任的数据。JEP 290引入的过滤机制为开发者提供了标准化的解决方案: 支持自定义过滤器满足特定场景需求 提供全局过滤器配置简化部署 内置RMI和DGC的安全过滤器 细粒度的过滤控制(类名、大小、深度等) 开发者应根据实际需求选择合适的过滤策略,优先考虑白名单方式,并结合JDK提供的过滤机制,有效缓解反序列化攻击风险。