0x01前言

因为前面学习了java的一些基础知识,java反序列化也算是搁置了很久的知识点,所以就来学习一下关于这个java反序列化的知识点

参考文章和视频:

JAVA反序列化漏洞总结-青叶

java序列化与反序列化全讲解

Java反序列化漏洞专题-基础篇(21/09/05更新类加载部分)

0x02正文

什么是java反序列化

Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存或文件中,实现跨平台通讯和持久化存储,而反序列化则指把字节序列恢复为 Java 对象的过程。(这个的话在之前学ctfshow里头的反序列化篇也有详细的介绍过)

为什么需要序列化

我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。发送方需要把这个Java对象转换为字节序列,然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象。

那么由此可以看出java序列化和反序列化的好处就是一是实现数据的存储二是实现数据的传输

序列化和反序列化的实现

  • ObjectOutputStream类的 writeObject() 方法可以实现序列化。

  • ObjectInputStream 类的 readObject() 方法用于反序列化。

只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)

我们先写个demo测试一下

先写个简单的类

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
// 导入 java.io.Serializable 接口(用于对象序列化)
import java.io.Serializable;

// 定义一个名为 Person 的类,并实现 Serializable 接口(表示该类支持序列化)
public class Person implements Serializable {

// 定义私有属性 name(姓名,String类型)
private String name;

// 定义私有属性 age(年龄,int类型)
private int age;

// 构造方法:用于创建 Person 对象时初始化 name 和 age
public Person(String name, int age) {
this.name = name; // 将传入的 name 赋值给当前对象的 name 属性
this.age = age; // 将传入的 age 赋值给当前对象的 age 属性
}

// 重写 Object 类的 toString() 方法(用于自定义对象的字符串表示)
@Override
public String toString() {
// 返回格式化的字符串,例如:Person[name=Alice, age=25]
return "Person[ name = " + name + ", age = " + age + "]";
}
}

直接把代码解释放在里面了

然后我们来写序列化的实现

1

那我们来看一下这两个接口是什么样的

Serializable 接口

Serializable 是java提供的标记接口,位于java.io包中,但是这个接口并没有任何内容(没有定义任何方法),它只是作为一个序列化能力的标识,意味着任何实现该接口的对象都可以实现序列化和反序列化的操作。