1. 序列化和反序列化
1.1 为啥需要序列化以及反序列化
其实序列化最终的目的是为了对象可以跨平台存储,和进行网络传输。而我们进行跨平台存储和网络传输的方式就是IO
,而我们的IO
支持的数据格式就是字节数组。
因为我们单方面的只把对象转成字节数组还不行,因为没有规则的字节数组我们是没办法把对象的本来面目还原回来的,所以我们必须在把对象转成字节数组的时候就制定一种规则(序列化),那么我们从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。
如果我们要把一栋房子从一个地方运输到另一个地方去,序列化就是我把房子拆成一个个的砖块放到车子里,然后留下一张房子原来结构的图纸,反序列化就是我们把房子运输到了目的地以后,根据图纸把一块块砖头还原成房子原来面目的过程1。
1.2 序列化的方式
序列化只是一种拆装组装对象的规则,那么这种规则肯定也可能有多种多样,比如现在常见的序列化方式有1:
JDK
(不支持跨语言)、JSON
(常见)、XML
、Hessian
、Kryo
(不支持跨语言)、Thrift
、Protostuff
、FST
(不支持跨语言)
说了以上这么多,大致理解了序列化和反序列化的作用,并且在实际场景中,反序列化会出现哪些问题?,以及如何挖掘以及防御呢?
2. JAVA 序列化与反序列化
首先上代码,现如今的程序语言都是面向对象的程序设计,那么我们先定义一个最简单的类,部分code
来源,出于对参考学习的文章作者的尊重,将会注明2。
对于需要反序列化的对象,需要继承Serializable
类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
import java.io.Serializable;
public class User implements Serializable{ private String name; public void setName(String name) { this.name=name; } public String getName() { return name; } }
|
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
|
import java.io.*;
public class Main { public static void main(String[] args) throws Exception { User user=new User(); user.setName("leshier"); byte[] serializeData=serialize(user); FileOutputStream fout = new FileOutputStream("user.bin"); fout.write(serializeData); fout.close(); User user2=(User) unserialize(serializeData); System.out.println(user2.getName()); } public static byte[] serialize(final Object obj) throws Exception { ByteArrayOutputStream btout = new ByteArrayOutputStream(); ObjectOutputStream objOut = new ObjectOutputStream(btout); objOut.writeObject(obj); return btout.toByteArray(); } public static Object unserialize(final byte[] serialized) throws Exception { ByteArrayInputStream btin = new ByteArrayInputStream(serialized); ObjectInputStream objIn = new ObjectInputStream(btin); return objIn.readObject(); } }
|
结果如下:


好了,到了这一步,我们试想,将对象改成恶意对象的话呢?

执行命令成功,证明这种方法是可行的,但是这种场景太完美了,现实场景中不会存在。
TODO