1 Java安全之反序列化

序列化与反序列化概述Java序列化是指把Java对象转换为字节序列的过程;这串字符可能被储存/发送到任何需要的位置,在适当的时候,再将它转回原本的 Java 对象,而Java反序列化是指把字节序列恢复为Java对象的过程 。
为什么需要序列化与反序列化当两个进程进行远程通信时,可以相互发送各种类型的数据 , 包括文本、图片、音频、视频等,而这些数据都会以二进制序列的形式在网络上传送 。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的 。如何做到呢?这就需要Java序列化与反序列化了 。换句话说,一方面,发送方需要把这个Java对象转换为字节序列 , 然后在网络上传送;另一方面,接收方需要从字节序列中恢复出Java对象
Java 提供了两个类 java.io.ObjectOutputStreamjava.io.ObjectInputStream 来实现序列化和反序列化的功能 , 其中 ObjectInputStream 用于恢复那些已经被序列化的对象 , ObjectOutputStream 将 Java 对象的原始数据类型和图形写入 OutputStream 。
在 Java 的类中 , 必须要实现 java.io.Serializablejava.io.Externalizable 接口才可以使用,而实际上 Externalizable 也是实现了 Serializable 接口
ObjectOutputStreamObjectOutputStream 继承的父类或实现的接口如下:

  • 父类 OutputStream:所有字节输出流的顶级父类,用来接收输出的字节并发送到某些接收器(sink) 。
  • 接口 ObjectOutput:ObjectOutput 扩展了 DataOutput 接口,DataOutput 接口提供了将数据从任何 Java 基本类型转换为字节序列并写入二进制流的功能,ObjectOutput 在 DataOutput 接口基础上提供了 writeObject 方法,也就是类(Object)的写入 。
  • 接口 ObjectStreamConstants:定义了一些在对象序列化时写入的常量 。常见的一些的比如 STREAM_MAGICSTREAM_VERSION 等 。
通过这个类的父类及父接口,我们大概可以理解这个类提供的功能:能将 Java 中的类、数组、基本数据类型等对象转换为可输出的字节,也就是反序列化 。接下来看一下这个类中几个关键方法
writeObject这是 ObjectOutputStream 对象的核心方法之一,用来将一个对象写入输出流中,任何对象 , 包括字符串和数组,都是用 writeObject 写入到流中的 。
之前说过,序列化的过程,就是将一个对象当前的状态描述为字节序列的过程 , 也就是 Object -> OutputStream 的过程 , 这个过程由 writeObject 实现 。writeObject 方法负责为指定的类编写其对象的状态,以便在后面可以使用与之对应 readObject 方法来恢复它
writeUnshared用于将非共享对象写入 ObjectOutputStream , 并将给定的对象作为刷新对象写入流中 。
使用 writeUnshared 方法会使用 BlockDataOutputStream 的新实例进行序列化操作,不会使用原来 OutputStream 的引用对象 。
writeObject0writeObjectwriteUnshared 实际上调用 writeObject0 方法,也就是说 writeObject0是上面两个方法的基础实现 。具体的实现流程将会在后面再进行详细研究 。
writeObjectOverride如果 ObjectOutputStream 中的 enableOverride 属性为 true,writeObject 方法将会调用 writeObjectOverride,这个方法是由 ObjectOutputStream 的子类实现的 。
在由完全重新实现 ObjectOutputStream 的子类完成序列化功能时,将会调用实现类的 writeObjectOverride 方法进行处理 。
ObjectInputStreamObjectInputStream 继承的父类或实现的接口如下:
  • 父类 InputStream:所有字节输入流的顶级父类 。
  • 接口 ObjectInput:ObjectInput 扩展了 DataInput 接口,DataInput 接口提供了从二进制流读取字节并将其重新转换为 Java 基础类型的功能,ObjectInput 额外提供了 readObject 方法用来读取类 。
  • 接口 ObjectStreamConstants:同上 。
ObjectInputStream 实现了反序列化功能,看一下其中的关键方法 。
readObject从 ObjectInputStream 读取一个对象 , 将会读取对象的类、类的签名、类的非 transient 和非 static 字段的值 , 以及其所有父类类型 。
我们可以使用 writeObjectreadObject 方法为一个类重写默认的反序列化执行方,所以其中 readObject 方法会 “传递性” 的执行,也就是说,在反序列化过程中,会调用反序列化类的

推荐阅读