什么是序列化和反序列化
Java序列化是指把Java对象转换为字节序列的过程,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
而Java反序列化是指把字节序列恢复为Java对象的过程。对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
- 需要对某些对象进行序列化,让它们离开内存空间,保存到文件中或数据库中,比如Web服务器中的Session对象。
- 通过RMI或网络上传输对象的时候。
怎么实现序列化和反序列化
ObjectOutputStream类writeObject() 方法可以实现序列化;ObjectInputStream类的readObject()方法可以实现反序列化。
序列化和反序列化可以理解为“写”和“读“的操作
//写入对象内容
private void writeObject(java.io.ObjectOutputStream out)
//读取对象内容
private void readObject(java.io.ObjectInputStream in)
需要注意的:
只有实现了Serializable接口的类的对象才可以被序列化。
如果该类有父类:
- 如果该父类已经实现了可序列化接口,则其父类的相应字段及属性的处理和该类相同;
- 如果该类的父类没有实现可序列化接口,则该类的父类所有的字段属性将不会序列化,并且反序列化时会调用父类的默认构造函数来初始化父类的属性,而子类却不调用默认构造函数,而是直接从流中恢复属性的值;
- 当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。
- 当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化
- 如果该类的某个属性标识为static类型的,则该属性不能序列化。
- 如果该类的某个属性采用transient关键字标识,则该属性不能序列化。
序列化和反序列化实例
Information.java
//定义了Information类,该类实现了Serializable接口
public class Information implements java.io.Serializable{
public String name;
//构造函数,初始化时执行
public Information(String name){
this.name=name;
}
}
SerializableDemo.java
import java.io.*;
public class SerializeDemo
{
public static void main(String [] args)
{
Information e = new Information("H4rdy");
try
{
//创建一个包含序列化对象的数据文件
FileOutputStream fileOut = new FileOutputStream("/tmp/information.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
//将序列化的内容写入文件
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/information.ser");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
将Information类序列化后保存到/tmp/information.ser文件中,information.ser文件中的内容:
aced 0005 是Java序列化的特征,流量中可以根据该特征发现序列化痕迹.
DeserializableDemo.java
import java.io.*;
public class DeserializeDemo
{
public static void main(String [] args)
{
Information e = null;
try
{
FileInputStream fileIn = new FileInputStream("/tmp/information.ser");
ObjectInputStream ins = new ObjectInputStream(fileIn);
//读取字节序列并反序列重建对象
e = (Information) ins.readObject();
ins.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Information class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Information...");
//恢复对象
System.out.println("Name: " + e.name);
}
}
读取information.ser并反序列化。
反序列化漏洞基本原理
重写readObject方法,从而执行自己的代码。
Information.java
import java.io.IOException;
public class Information implements java.io.Serializable{
public String name;
//重写readObject方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法以便完成反序列化操作
in.defaultReadObject();
//执行打开计算器程序命令
Runtime.getRuntime().exec("open /Applications/Calculator.app/");
}
public Information(String name){ //构造函数,初始化时执行
this.name=name;
}
}