Java反序列化之原生
字数 1194 2025-08-12 11:34:33

Java反序列化安全教学文档

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

1.1 定义

  • 序列化:将Java对象转换为字节序列的过程
  • 反序列化:将字节序列恢复为Java对象的过程

1.2 主要用途

  1. 数据持久化:将对象保存到文件或数据库中
  2. 远程通信:通过网络传输对象
  3. RMI(远程方法调用)传输对象

二、序列化与反序列化实现

2.1 序列化示例代码

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(
            new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    
    public static void main(String[] args) throws Exception {
        Person person = new Person("xinyuan", 22);
        serialize(person);
        System.out.println(person);
    }
}

2.2 反序列化示例代码

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializationTest {
    public static Object unserialize(String Filename) 
        throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(
            new FileInputStream("ser.bin"));
        Object obj = ois.readObject();
        return obj;
    }
    
    public static void main(String[] args) throws Exception {
        Person person = (Person) unserialize("ser.bin");
        System.out.println(person);
    }
}

2.3 可序列化类实现

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;
    
    public Person() {}
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Person{" + "name='" + name + "', age=" + age + '}';
    }
}

三、反序列化安全问题

3.1 安全问题产生原因

当服务端反序列化数据时,客户端传递类的readObject方法中的代码会自动执行,这可能导致攻击者在服务器上运行任意代码。

3.2 攻击利用条件

  1. 共同条件

    • 类继承Serializable接口
    • 存在入口类(source)
    • 存在执行类(sink)
    • 存在完整的调用链(gadget chain)
  2. 入口类要求

    • 重写readObject方法
    • 参数类型宽泛(最好使用JDK自带类)
    • Map<Object, Object>
  3. 调用链要求

    • 方法名称和类型相同
    • 能够连接source和sink

3.3 常见攻击形式

形式1:入口类的readObject直接调用危险方法

在Person类中重写readObject方法,序列化后,反序列化时执行危险操作。

形式2:入口类参数中包含可控类,该类有危险方法,readObject时调用

形式3:入口类参数包含可控类,该类又调用其他有危险方法的类,readObject时调用

四、关键方法解析

4.1 writeObject和readObject

  • Java在序列化对象时会调用对象的writeObject方法
  • 反序列化时会调用readObject方法
  • 开发者可以自定义这两个方法来实现特殊序列化/反序列化逻辑

4.2 类比理解

  • 序列化:类似快递打包,可以自定义打包方式(重写writeObject)
  • 反序列化:类似拆快递,可以自定义拆包方式(重写readObject)

五、常见序列化协议

  1. XML & SOAP
  2. JSON
  3. Protobuf(Protocol Buffers)

六、Java与PHP反序列化对比

  • Java中大量库会实现readObjectwriteObject方法
  • PHP中__wakeup__sleep方法较少使用
  • Java反序列化需要开发者更多参与,因此潜在风险点更多

七、防御措施

  1. 避免反序列化不可信数据
  2. 使用白名单验证反序列化的类
  3. 使用安全的替代方案如JSON
  4. 对序列化数据进行签名验证
  5. 更新JDK版本,利用内置防护机制

八、总结

Java反序列化漏洞是一种严重的安全威胁,攻击者可以通过精心构造的序列化数据在目标系统上执行任意代码。理解其原理和利用方式对于开发安全的应用至关重要。开发者应当谨慎处理反序列化操作,并采取适当的安全措施来防范此类攻击。

Java反序列化安全教学文档 一、序列化与反序列化基础概念 1.1 定义 序列化 :将Java对象转换为字节序列的过程 反序列化 :将字节序列恢复为Java对象的过程 1.2 主要用途 数据持久化:将对象保存到文件或数据库中 远程通信:通过网络传输对象 RMI(远程方法调用)传输对象 二、序列化与反序列化实现 2.1 序列化示例代码 2.2 反序列化示例代码 2.3 可序列化类实现 三、反序列化安全问题 3.1 安全问题产生原因 当服务端反序列化数据时,客户端传递类的 readObject 方法中的代码会自动执行,这可能导致攻击者在服务器上运行任意代码。 3.2 攻击利用条件 共同条件 : 类继承 Serializable 接口 存在入口类(source) 存在执行类(sink) 存在完整的调用链(gadget chain) 入口类要求 : 重写 readObject 方法 参数类型宽泛(最好使用JDK自带类) 如 Map<Object, Object> 调用链要求 : 方法名称和类型相同 能够连接source和sink 3.3 常见攻击形式 形式1:入口类的readObject直接调用危险方法 在Person类中重写readObject方法,序列化后,反序列化时执行危险操作。 形式2:入口类参数中包含可控类,该类有危险方法,readObject时调用 形式3:入口类参数包含可控类,该类又调用其他有危险方法的类,readObject时调用 四、关键方法解析 4.1 writeObject和readObject Java在序列化对象时会调用对象的 writeObject 方法 反序列化时会调用 readObject 方法 开发者可以自定义这两个方法来实现特殊序列化/反序列化逻辑 4.2 类比理解 序列化:类似快递打包,可以自定义打包方式(重写writeObject) 反序列化:类似拆快递,可以自定义拆包方式(重写readObject) 五、常见序列化协议 XML & SOAP JSON Protobuf (Protocol Buffers) 六、Java与PHP反序列化对比 Java中大量库会实现 readObject 、 writeObject 方法 PHP中 __wakeup 、 __sleep 方法较少使用 Java反序列化需要开发者更多参与,因此潜在风险点更多 七、防御措施 避免反序列化不可信数据 使用白名单验证反序列化的类 使用安全的替代方案如JSON 对序列化数据进行签名验证 更新JDK版本,利用内置防护机制 八、总结 Java反序列化漏洞是一种严重的安全威胁,攻击者可以通过精心构造的序列化数据在目标系统上执行任意代码。理解其原理和利用方式对于开发安全的应用至关重要。开发者应当谨慎处理反序列化操作,并采取适当的安全措施来防范此类攻击。