Java安全学习(序列化和反序列化)
Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化,将Java对象转为字节序列。
Java 反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化。
String、Integer、数组、Object对象等Java内置的数据类型均可实现序列化,自己写的类只要实现了Serializable接口即可实现序列化和反序列化。
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class vultest{
public static void main(String[] args) throws Exception{
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("person.dat"));
objectOutputStream.writeObject(new Person("zhangsan",20));
objectOutputStream.flush();
objectOutputStream.close();
}
}
class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
这段代码将一个我自己设计的类person类序列化存储到了一个文件person.dat里面
值得注意的是 java的序列化与反序列化和php的有所不同
php的序列化是将其序列化成一个字符串 而java是将一个对象从内存中序列化到一个文件中存储
我们都知道在php中有各种魔术方法__destruct __toString等等 在一定的条件下就会自动去调用这些魔术方法
但是在java中没有这些 只有readobject和writeobject 什么意思呢 也就是说 我们将一个对象序列化成文件的时候会自动调用writeobject方法 在将一个文件恢复成一个对象的时候会自动调用readobject
我们可以下面演示一下
在person类中自己写一个writeobject这个方法
private void writeObject(ObjectOutputStream objectOutputStream) throws Exception{
objectOutputStream.defaultWriteObject();
Runtime.getRuntime().exec("calc");
}
这样既实现了序列化过程又执行了用户自己的一些代码 相当于php中的__sleep方法 而反序列化则相当于__wakeup方法
注意我们在写这一个方法的时候需要有形参为ObjectOutputStream类型的对象且可见性修辞为private才能正常的访问到这个方法 需要实现默认的也就是 defaultWriteObject
方法
反序列化也同理
java中的序列化与反序列化也就这一点 但是真正的分析漏洞还在后面 因为程序员不会傻逼到把命令执行写在这两个方法中
借用y4er大佬博客中的一段话就是
但是你肯定会问,真正开发的时候谁会这么写啊,这不是故意写bug吗?确实,开发人员不会这么写,但是在重写 readObject()
方法时会写一些正常的操作,我们这个时候就要提到反射了,关于更多java反序列化的问题请移步 深入分析Java的序列化与反序列化。
在java中,反序列化很大部分是通过反射来构造pop链。