开启 java 安全学习第二站,java 序列化与反序列化
0x01 意义
我们都知道就算是一条内裤都有它的作用和意义,那么序列化和反序列化存在的意义又是什么呢?也就是说我们可以用这东西来干什么?
实现两个进程间对象的传输
这个就是 java 序列化和反序列化的定义了,前者将对象转化为字节流数据,后者将字节流数据还原为对象
实现数据的持久化
对象序列化之后可以把字节数据写入文件中(硬盘里),这样就可以减轻内存的负担,再用的时候反序列化还原即可。比如配置信息,用户的数据等等。
规范传递格式,方便网络传输
这个也很好理解,文本音频视频这些数据全被序列化为二进制数据了,当然很好传输。
0x02 序列化与反序列化的实现
序列化的实现
- 实现 Serializable 接口:将要序列化的类实现 Serializable 接口。
- 创建ObjectOutputStream:创建一个ObjectOutputStream对象,用于将对象序列化为字节流。
- 写入对象:使用writeObject()方法将对象写入到输出流中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable;
class Student implements Serializable { private String name; private int age;
public Student(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; } public int getAge() { return age; } }
public class Serialization { public static void main(String[] args) { Student stu = new Student("she11F",18); try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.bin"))){ oos.writeObject(stu); }catch(IOException e){ e.printStackTrace(); } } }
|
这样把一个学生的实例序列化成了二进制数据,并且写入了 student.bin 文件中

反序列化的实现
- 创建 ObjectInputStream:创建一个ObjectInputStream对象,用于从字节流中读取对象。
- 读取对象:使用 readObject() 方法从输入流中读取对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import java.io.FileInputStream; import java.io.ObjectInputStream;
public class DeSerialization { public static void main(String[] args) { try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.bin"))){ Student stu = (Student) ois.readObject(); System.out.println(stu.getName()); System.out.println(stu.getAge()); }catch(Exception e){ e.printStackTrace(); } } }
|

0x03 漏洞
jdk 提供重写 writeObject,readObject 的权限
1 2
| private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException
|
而且默认执行用户重写的,用户没有重写则调用系统的。那我们重写 readObject 夹带危险函数,那么服务器端反序列化的时候就有可能中招了
我们在 Student 类里重新定义 readObject
1 2 3 4
| private void readObject(ObjectInputStream ois)throws java.io.IOException, ClassNotFoundException{ ois.defaultReadObject(); Runtime.getRuntime().exec("calc.exe"); }
|
然后序列化这个类再反序列化就会弹计算器了,当然现实开发中不太可能暴漏这种接口,所以得学其他思想,我先去学了,后面再做补充