第十二章 序列化

第八十五条:其他方法优先于Java序列化

序列化:将对象编码成字节流。反序列化:从字节流编码中重新构建对象。

序列化的根本问题在于,其攻击面过于庞大,无法进行防护,并且它还在不断的扩大。

避免序列化攻击的最佳方式是永远不要反序列化任何东西。

在新编写的任何系统中都没有理由再使用Java序列化。

永远不要反序列化不被信任的数据。

白名单优于黑名单。

第八十六条:谨慎的实现Serializable接口

实现Serializable接口而付出的最大代价是,一旦一个类被发布,就大大降低了“改变这个类的实现”的灵活性。

实现Serializable的第二个代价是,它增加了出现BUG和安全漏洞的可能性。

实现Serializable的第三个代价是,随着类发行的版本,相关的测试负担也会增加。

为了继承而设计的类应该尽可能少的去实现Serializable接口,用户的接口也应该尽可能少继承Serializable接口。

内部类不应该实现Serializable接口。

第八十七条:考虑使用自定义的序列化形式

如果事先没有认真考虑默认的序列化形式是否合适,则不要贸然接受。

如果一个对象的物理表示法等同于他的逻辑内容,可能就适合于使用默认的序列化形式。

即使你确认默认的序列化形式是合适的,通常还必须提供一个readObject方法以保证约束关系和安全性。

当一个对象的物力表示法与他的逻辑数据内容有实质性的区别时,使用默认序列化形式会有以下四个缺点:
它使这个类的导出API永远的束缚在该类的内部表示法上。
他会消耗过多的空间。
他会消耗过多的时间。
他会引起栈溢出。

在决定将一个域做成非瞬时的之前,请一定要确信它的值将是该对象逻辑状态的一部分。

如果在读取整个对象状态的任何其他方法上强制任何同步,则也必须在对象序列上强制这种同步。

不管你选择了哪种序列化形式,都要为自己编写的每个可序列化的类声明一个显式的序列。版本UID。

不要修改序列版本UID,否则将会破坏类现有的已被序列化实例的兼容性。

第八十八条:保护性的编写readObject方法

当一个对象被反序列化的时候,对于客户端不应该拥有的对象引用,如果哪个域包含了这样的对象引用,就必须要做保护性拷贝,这是非常重要的。

编写出更加健壮readObject方法的指导方针:
对于对象引用域必须保持为私有的类,要保护性的拷贝这些域中的每个对象。不可变类的可变组件就属于这一类别。
对于任何约束条件,如果检查失败,则抛出一个InvalidObjectException异常。这些检查动作应该跟在所有的保护性拷贝之后。
如果整个对象图在被反序列化之后必须进行验证,就应该使用ObjectInputValidation接口。
无论是直接方式还是间接方式,都不要调用类中任何可被覆盖的方法。

第八十九条:对于实例控制,枚举类型优于readResolve

如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域则都必须声明为transient。

readResolve的可访问性很重要。

第九十条:考虑用序列化代理代替序列化实例

序列化代理模式:
首先,为可序列化的类设计一个私有的嵌套类,精确的表示外围类的实例的逻辑状态。这个嵌套类被称作序列化代理,他应该有一个单独的构造器,其参数类型就是那个外围类。
接下来,将下面的writeReplace方法添加到外围类中,通过序列化处理,这个方法可以被逐字的复制到任何类中。
最后,在SerializationProxy类中提供一个readResolve方法,它返回一个逻辑上相当的外围类的实例。

序列化代理方法可以阻止伪字节流的攻击以及内部域的盗用攻击。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值