《Effective Java》-序列化

序列化

Item 85: Prefer alternatives to Java serialization

其他方法优先于Java序列化

使用Java中的readObject()方法进行反序列化是非常有风险的。

其一,为反序列化提供精心编写的代码流,则攻击者可以在底层硬件中执行本机的的任意代码。

其二,当攻击者向服务发送反序列化炸弹(deserialize bomb),就能够轻易完成一次拒绝服务(Denail of Service)攻击。

避免序列化攻击的最佳方式就是永远不要反序列化任何东西。 没有理由在你写的任何程序中使用Java序列化。

如果非要使用Java序列化,使用Java 9 支持的java.io.ObjectInputFilter

Item 86: Implement Serializable with great caution

谨慎地实现Serializable接口。

实现Serializable接口最大的代价就是,一旦某个类被发布,被存储在硬盘中,他可修改的灵活性就大大降低了。

如果使用了默认的序列化方式,一旦类的内部形式发生改变,那么发序列化老数据的时候,就会产生兼容性的问题。

实现序列化接口的第二个代价就是,会增加安全漏洞以及BUG的几率。通过序列化来创建对象,是一种超出语言之外的机制,很容易跳过系统的安全检查。

第三个代价是,增加了新类的测试负担。

如果一个专门为继承而生的类,和接口应当尽可能少地去实现序列化接口。内部类不应该去实现序列化接口

Item 87: Consider using a custom serialized form

考虑使用自定义的序列化形式。

在深思熟虑之前,不要贸然接受默认的序列化形式。

如果一个对象的物理表现形式和逻辑内容相同,可以考虑使用默认的序列化形式。不过,即使你确定了使用默认的序列化形式是合适的,依旧需要提供一个readObject方法来确保约束关系和安全性。

如果将某些字段设置为transient,那么反序列化的时候,字段值将会被初始化为默认值。如果是引用数据类型,则为null,基本数据类型则为0或者false。如果不能接受的话,必须提供readObject,在其实现内为你想要的属性去赋值。

此外,如果你在读取对象状态的其他方法上施加了同步,则也必须在序列化上强制这种同步。

一定要为实现序列化接口的类显式地声明一个序列化UID。不要去随意修改这个UID,除非你想要放弃系统的兼容性。

Item 88: Write readObject methods defensively

保护性地编写readObejct方法

当一个对象被反序列化的时候,若其某个字段包含客户端不存在的引用,则对此字段的保护性拷贝是至关重要的。

可以通过一个石蕊测试来确定,你是应该使用默认的readObject还是需要定义自己的readObject:你觉得为所有的非transient字段都添加到一个公有构造器,并且并施加任何参数校验是否合适?

禁止在readObject方法中引用任何用于被重写的方法。

Item 88: For instance control, prefer enum types to readResolve

为了控制实例,枚举类型优先于readResolve

对于任何的readObject方法,无论是显式的还是默认的,都会返回一个新的实例,该实例不同于创建时的实例。

readResolve的上述性质会破坏单例模式,为了保证单例的性质,可以使用枚举类对象。

事实上,如果你依赖于readResolve控制实例,所有的字段都应该被声明为transient的。

Item 90: Consider serialization proxies instead of seriallized instance

考虑使用序列化代理替代序列化实例

序列化模式相当简单:

  1. 为可序列化的类设计一个私有的静态嵌套类,精确表示外围类的逻辑状态
  2. 嵌套类的参数类型是外围类,并且拥有一个构造方法
  3. 构造器只从其参数中来复制值,而不做任何参数检查或者保护性拷贝

序列化代理有两个局限性:

  1. 不能与可以被客户端扩展的类相兼容
  2. 序列化代理模式增强的功能和安全性并不是没有代价的,保护性拷贝会降低系统的运行效率
相关推荐
方圆想当图灵1 小时前
如何让百万 QPS 下的服务更高效?
分布式·后端
凤山老林2 小时前
SpringBoot 轻量级一站式日志可视化与JVM监控
jvm·spring boot·后端
凡梦千华2 小时前
Django时区感知
后端·python·django
Chan162 小时前
JVM从入门到实战:从字节码组成、类生命周期到双亲委派及打破双亲委派机制
java·jvm·spring boot·后端·intellij-idea
烈风4 小时前
004 Rust控制台打印输出
开发语言·后端·rust
用户21411832636024 小时前
用 AI 一键搞定!中医药科普短视频制作升级版
后端
秋难降4 小时前
零基础学习SQL(十一):SQL 索引结构|从 B+Tree 到 Hash,面试常问的 “为啥选 B+Tree” 有答案了
数据库·后端·mysql
SamDeepThinking5 小时前
用设计模式重构核心业务代码的一次实战
java·后端·设计模式
用户49055816081257 小时前
lvs会话同步
后端