@Author: Patrilic @Time: 2020-3-18 11:26:55
Java中只需要实现 java.io.Serializable 或者 java.io.Externalizable 接口即可执行序列化操作
构造一个调用类,其中,Exployee类实现了 java.io.Serializable 接口 :
package com.patrilic.testSer;
public class Employee implements java.io.Serializable
{
public String name;
public String identify;
public void mailCheck()
{
System.out.println("This is the "+this.identify+" of our company");
}
}
序列化操作, 在调用Employee类时,所有的数据都会被序列化
package com.patrilic.testSer;
import com.patrilic.testSer.Employee;
//import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;
import java.io.*;
public class Step1 {
public static void main(String [] args) {
Employee e = new Employee();
e.name = "员工甲";
e.identify = "General staff";
try {
// 打开一个文件输入流
FileOutputStream fileOut =
new FileOutputStream("/tmp/test.db");
// 建立对象输入流
ObjectOutputStream out = new ObjectOutputStream(fileOut);
//输出反序列化对象
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/test.db");
}catch(IOException i)
{
i.printStackTrace();
}
}
}
反序列化操作
package com.patrilic.testSer;
import java.io.*;
public class Step2
{
public static void main(String [] args)
{
Employee e = null;
try
{
// 打开一个文件输入流
FileInputStream fileIn = new FileInputStream("/tmp/test.db");
// 建立对象输入流
ObjectInputStream in = new ObjectInputStream(fileIn);
// 读取对象
e = (Employee) in.readObject();
in.close();
fileIn.close();
}catch(IOException i)
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)
{
System.out.println("Employee class not found");
c.printStackTrace();
return;
}
System.out.println("Deserialized Employee...");
System.out.println("Name: " + e.name);
System.out.println("This is the "+e.identify+" of our company");
}
}
Java反序列化中,会调用被反序列化的readObject方法,如果readObject方法是恶意的,那么就会引发漏洞
package com.patrilic.testSer;
import java.io.*;
public class test{
public static void main(String args[]) throws Exception{
UnsafeClass Unsafe = new UnsafeClass();
Unsafe.name = "hacked by ph0rse";
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
//writeObject()方法将Unsafe对象写入object文件
os.writeObject(Unsafe);
os.close();
//从文件中反序列化obj对象
FileInputStream fis = new FileInputStream("object");
ObjectInputStream ois = new ObjectInputStream(fis);
//恢复对象
UnsafeClass objectFromDisk = (UnsafeClass)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
}
class UnsafeClass implements Serializable{
public String name;
//重写readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行命令
System.out.println("my First!");
Runtime.getRuntime().exec("open -a Calculator.app");
}
}
这里进行反序列化操作时,使用 ObjectInputStream 读取序列化文件,然后调用了 readObject() , 当然就会成功的执行命令
并且确实是先执行了readObject类的操作,然后再进行 System.out.println(name)
序列化对象: java.io.ObjectOutputStream -> writeObject()
反序列化对象: java.io.ObjectInputStream -> readObject()
也就是说在序列化类时,就会自动去
java.io.Serializable接口是空接口,仅仅用于表示这个类可序列化
package com.patrilic.demo;
import java.io.*;
import java.util.Arrays;
public class DeserializationTest implements Serializable {
private String username;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// 创建DeserializationTest类,并类设置属性值
DeserializationTest t = new DeserializationTest();
t.setUsername("Patrilic");
t.setEmail("admin@patrilic.top");
// 创建Java对象序列化输出流对象
ObjectOutputStream out = new ObjectOutputStream(baos);
// 序列化DeserializationTest类
out.writeObject(t);
out.flush();
out.close();
// 打印DeserializationTest类序列化以后的字节数组,我们可以将其存储到文件中或者通过Socket发送到远程服务地址
System.out.println("DeserializationTest类序列化后的字节数组:" + Arrays.toString(baos.toByteArray()));
// 利用DeserializationTest类生成的二进制数组创建二进制输入流对象用于反序列化操作
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
// 通过反序列化输入流(bais),创建Java对象输入流(ObjectInputStream)对象
ObjectInputStream in = new ObjectInputStream(bais);
// 反序列化输入流数据为DeserializationTest对象
DeserializationTest test = (DeserializationTest) in.readObject();
System.out.println("用户名:" + test.getUsername() + ",邮箱:" + test.getEmail());
// 关闭ObjectInputStream输入流
in.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
java.io.Externalizable继承Serializable接口,定义了两个方法:
package com.patrilic.demo;
import java.io.*;
import java.util.Arrays;
public class ExternalizableTest implements java.io.Externalizable {
private String username;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(username);
out.writeObject(email);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.username = (String) in.readObject();
this.email = (String) in.readObject();
}
public static void main(String[] args) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// 创建DeserializationTest类,并类设置属性值
ExternalizableTest t = new ExternalizableTest();
t.setUsername("Patrilic");
t.setEmail("admin@patrilic.top");
// 创建Java对象序列化输出流对象
ObjectOutputStream out = new ObjectOutputStream(baos);
// 序列化DeserializationTest类
out.writeObject(t);
out.flush();
out.close();
// 打印ExternalizableTest类序列化以后的字节数组,我们可以将其存储到文件中或者通过Socket发送到远程服务地址
System.out.println("ExternalizableTest类序列化后的字节数组:" + Arrays.toString(baos.toByteArray()));
// 利用ExternalizableTest类生成的二进制数组创建二进制输入流对象用于反序列化操作
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
// 通过反序列化输入流(bais),创建Java对象输入流(ObjectInputStream)对象
ObjectInputStream in = new ObjectInputStream(bais);
// 反序列化输入流数据为DeserializationTest对象
ExternalizableTest test = (ExternalizableTest) in.readObject();
System.out.println("用户名:" + test.getUsername() + ",邮箱:" + test.getEmail());
// 关闭ObjectInputStream输入流
in.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
值得注意的是两个方法的重写: