Java反序列化之原生
字数 1194 2025-08-12 11:34:33
Java反序列化安全教学文档
一、序列化与反序列化基础概念
1.1 定义
- 序列化:将Java对象转换为字节序列的过程
- 反序列化:将字节序列恢复为Java对象的过程
1.2 主要用途
- 数据持久化:将对象保存到文件或数据库中
- 远程通信:通过网络传输对象
- 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 攻击利用条件
-
共同条件:
- 类继承
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反序列化漏洞是一种严重的安全威胁,攻击者可以通过精心构造的序列化数据在目标系统上执行任意代码。理解其原理和利用方式对于开发安全的应用至关重要。开发者应当谨慎处理反序列化操作,并采取适当的安全措施来防范此类攻击。