序列化与反序列化

概念

Serialization(序列化):将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。

deserialization(反序列化):将保存在磁盘文件中的java字节码重新转换成java对象称为反序列化

优点

说一个跟我们网安息息相关的,利用序列化实现远程通信,在网络上传输字节序列

相关api

JDK类库提供的序列化API:

1
2
3
4
5
java.io.ObjectOutputStream    
表示对象输出流,其中writeObject(Object obj)方法可以将给定参数的obj对象进行序列化,将转换的一连串的字节序列写到指定的目标输出流中。

java.io.ObjectInputStream
该类表示对象输入流,该类下的readObject(Object obj)方法会从源输入流中读取字节序列,并将它反序列化为一个java对象并返回。

序列化与反序列化

创建一个可以被序列化的类,实现序列化的类对象必须实现了Serializable类或Externalizable类才能被序列化,否则会抛出异常,我们熟知的java执行命令的Runtime是不可以被序列化的

image-20230321113117201

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
34
35
36
37
38
39
40
41
42
43
44
45
import java.io.Serializable;//导入io包下的序列化类

//创建实现序列化接口的学生类
public class Student implements Serializable {
//私有化成员变量
private String name;
private char sex;
private int year;

public Student() { //无参构造
}

public Student(String name, char sex, int year) {
//参数给属性赋值
this.name = name;
this.sex = sex;
this.year = year;
}

//重写set和get
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public char getSex() {
return sex;
}

public void setSex(char sex) {
this.sex = sex;
}

public int getYear() {
return year;
}

public void setYear(int year) {
this.year = year;
}

}

实现序列化与反序列化

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
34
35
36
37
38
39
40
import java.io.*;
import java.io.Externalizable;
/*
把student类对象序列化到文件C:\\Java\\Student\\Student1.txt
*/
public class UserStudent {
public static void main(String[] args) throws IOException, ClassNotFoundException {

Student st = new Student("xiu", 'M', 18);//利用有参构造实例化一个用于序列化反序列化的类
File file=new File("C:\\\\Java\\\\Student\\\\Student1.txt");//判断Student1.txt是否存在
if (file.exists()){
System.out.println("文件存在");
}else{
file.createNewFile();//文件不存在就创建文件
}

try{
FileOutputStream fos = new FileOutputStream(file);//对象st序列化过程
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(st);

fos.close();
oos.close();

FileInputStream fis = new FileInputStream(file);//对象st反序列化为st1的过程
ObjectInputStream ois = new ObjectInputStream(fis);
Student st1 = (Student) ois.readObject();

System.out.println("name = " + st1.getName());//利用get获取对象st1的属性
System.out.println("sex = " + st1.getSex());
System.out.println("year = " + st1.getYear());
ois.close();
fis.close();

}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}

漏洞所在

在实际开发过程中往往会重写readObject()方法,当readObject()方法中存在代码块时反序列化的属狗会直接调用执行,这种情况很少,往往出现的是该readObject()方法存在一个无害的的类,但是这个类调用了危险的类,最终实现代码执行