Hi!我是小小,今天是本周的第四篇,本篇将会着重讲解关于Java序列化的内容
Java序列化
java序列化和反序列化数据,是通过ObjectOutputStream和ObjectInputStream这两个类来实现的,
举个例子:
要序列化的对象data1
序列化操作类SerializeTest
执行后会发现 序列化成功,输出文件data1,同时反序列化成功,我们可以从data1文件中反序列化出data1类,能够获取其中的信息。
我们看看data1文件, notepad打开它长这样
再按十六进制打开看看,
是的,这就是序列化。
Java序列化缺陷
无法跨语言
Java序列化目前只支持Java语言实现的框架,其它语言大部分都没有使用Java的序列化框架,也没有实现Java序列化这套协议,因此,如果两个基于不同语言编写的应用程序之间通信,使用Java序列化,则无法实现两个应用服务之间传输对象的序列化和反序列化。
容易被攻击
Java官网安全编码指导方针里有说明,“对于不信任数据的反序列化,从本质上来说是危险的,应该避免“。可见Java序列化并不是安全的。
我们知道对象是通过在 ObjectInputStream 上调用 readObject() 方法进行反序列化的,这个方法其实是一个神奇的构造器,它可以将类路径上几乎所有实现了 Serializable 接口的对象都实例化。这也就意味着,在反序列化字节流的过程中,该方法可以执行任意类型的代码,这是非常危险的。
对于需要长时间进行反序列化的对象,不需要执行任何代码,也可以发起一次攻击。攻击者可以创建循环对象链,然后将序列化后的对象传输到程序中反序列化,这种情况会导致 hashCode 方法被调用次数呈次方爆发式增长, 从而引发栈溢出异常。例如下面这个案例就可以很好地说明。
实现攻击的原理:Apache Commons Collections允许链式的任意的类函数反射调用,攻击者通过实现了Java序列化协议的端口,把攻击代码上传到服务器上,再由Apache Commons Collections里的TransformedMap来执行。
序列化后的流太大
序列化后的二进制流大小能体现序列化的性能。序列化后的二进制数组越大,占用的存储空间就越多,存储硬件的成本就越高。如果我们是进行网络传输,则占用的带宽就更多,这时就会影响到系统的吞吐量。
Java 序列化中使用了 ObjectOutputStream 来实现对象转二进制编码,那么这种序列化机制实现的二进制编码完成的二进制数组大小,相比于 NIO 中的 ByteBuffer 实现的二进制编码完成的数组大小,有没有区别呢?
结果
性能太差
如果序列化的速度慢,就会影响网络通信的效率,从而增加系统的响应时间。
运行结果
总结
Java 默认的序列化是通过 Serializable 接口实现的,只要类实现了该接口,同时生成一个默认的版本号,就可以实现序列化
序列化存在存在安全漏洞、不跨语言以及性能差等缺陷,
FastJson、Protobuf、Kryo 是比较有特点的,而且性能以及安全方面都得到了业界的认可,我们可以结合自身业务来选择一种适合的序列化框架
关于作者
我是小小,双鱼座的程序猿,我们下期再见~bye~
END
「 往期文章 」
领取专属 10元无门槛券
私享最新 技术干货