第十二章 序列化

讨论对象的序列化 把对象编码成字节流(序列化),并从字节流编码中重新构建对象(反序列化)
本章关注序列化的风险,以及将风险降到最低

第八十五条 ,其他方法优先于java序列化
1.反序列化炸弹

    //创建了201个对象,而以指数级的插入2的100次方的HashMap
    public  static byte[] bomb(){
            Set<Object> root = new HashSet<>();
            Set<Object> s1 = root;
            Set<Object> s2 = new HashSet<>();
            for (int i = 0; i < 100; i++) {
                Set<Object> t1 = new HashSet<>();
                Set<Object> t2 = new HashSet<>();
                t1.add("foo");
                s1.add(t1);s1.add(t2);
                s2.add(t1);s2.add(t2);
                s1=t1;
                s2=t2;
            }
            return serialize(root);
        }

2.避免序列化攻击的最佳方式是永远不要序列化任何东西,在新编写的任何新的系统中都没理由再使用java序列化,
永远不要反序列化不被信任的数据
3.可以使用json和protocol
4.java9提供了对象反序列化过滤器,它可以在数据流被反序列化之前,为他们定义一个过滤器,他可以操作粒度,
允许接受或者拒绝某些类,默认接受类,拒绝可能存在危险的黑名单;默认拒绝类,接受白名单安全的类。白名单
优先于黑名单,有一个工具SWAT,他可以替应用准备好白名单

第八十六条,谨慎地实现serializable接口
1.实现serializable接口而付出的最大代价是,一旦一个类被发布,就大大降低了改变这个类的实现的灵活性,新旧序
列化文件兼容的问题
2.serializable需要添加一个UID,来保证兼容,不加系统自动生成一个,但是是根据类的信息来生成的,如果增加一个
静态方法,可能生成的UID就不一样
3.实现serializable的第二个代价是,它增加了出现的Bug和安全漏洞的可能性(85)
4.实现serializable的第三个代价是,随着类发行新的版本,相关的测试负担也会增加,需要兼容旧版,测试可序列化类
* 版本的乘积
5.实现serializable接口并不是一个很轻松就可以做出的决定
6.为了继承而设计的类应该尽可能少地去实现serializable接口,用户的接口也应该尽可能少继承serializable接口
7.如果带有一个实例域的类,实例域有一些限制条件,防止子类覆盖finalize方法,造成终结器的攻击,需要
覆盖finalize并设置为final
8.如果类有限制条件,当类的实例域被初始化成默认值,就会违背这些限制条件,需要添加一个private void
readObjectNoData()
9.如果一个为了继承而设计的类是不可序列化的,那么子类序列化就需要调用父类无参的构造器,如果没有提供,
子类被迫使用序列化代理模式(90)
10.内部类不应该实现serializable接口,他们使用编译器的合成域来保存指向外围实例的引用,以及保存外围作用域的局
部变量的值,这些域如何对应到对应的类定义中并没有明确的规定,就好像没有指定匿名类和局部类的名称一样
因此,内部类的默认序列化形式是定义不清楚的,然而,静态成员类却可以实现serializable接口

第八十七条,考虑使用自定义的序列化形式
1.如果事先没有认真考虑默认的序列化形式是否合适,则不要贸然接受
2.如果一个对象的物理表示法等同于它的逻辑内容,可能就适合于使用默认的序列化形式
3.即使你确定了默认的序列化形式是合适的,通常还必须提供一个readObject方法以保证约束关系和安全性
4.@serial和@serialData 告诉javadoc把文档信息放在有关序列化形式的特殊文档页中
5.当一个对象的物理表示法与它的逻辑数据内容有实质性的区别时,使用默认的序列化形式会有以下4个缺点
1.它使这个类的导出API永远地束缚在该类的内部表示法上
2.它会消耗更多的空间
3.它会消耗过多的时间
4.它会引起栈溢出

6.@transient忽略序列化 ,在决定将一个域非transient之前,请一定确信它的值将是该对象逻辑状态的一部分
7.defaultReadObject和defaultWriteObject可以兼容前后版本,没有的多的域可以忽略
8.readObject可以恢复那些被@transient忽略序列化的域的值,先调用defaultReadObject;然后恢复那些值;或者这些transient值
可以在第一次访问的时候自动恢复
9.如果在读取整个对象状态的任何其他方法上强制任何同步,则也必须在对象序列化上强制这种同步没,否则可能
资源排列死锁问题
10.不管你选择了哪种序列化形式,都要为自己编写的每个可序列化的类声明一个显式的序列化UID
private static final long serialVersionUID = randomLongValue;
11.不要修改序列化版本UID,否则将会破坏类现有的已被序列化实例的兼容性

第八十八条,保护性地编写readObject方法(防止恶意的字节码)
1.当一个对象被反序列化的时候,对于客户端不应该拥有的对象引用,如果那个域包含了这样的对象引用,就必须要
做保护性拷贝,这是非常常重要的
2.readObject不要调用可覆盖的方法,不管是直接或者间接,在子类的状态被反序列化之前会先执行
3.编写健壮的readObject
1.对于对象引用域必须保持为私有的类,要保护性地拷贝这些域中的每个对象,不可变的类的可变组件就属于这一
类别
2.对于任何约束条件,如果检查失败,则抛出一个InvalidObjectException异常,这些检查动作应该跟在所有的保护性
拷贝之后
3.如果整个对象图在反序列化之后必须进行验证,就应该使用ObjectInputValidation接口
4.不管是直接或者间接,都不要调用任何可被覆盖的方法

第八十九条,对于实例控制,枚举类型优先于readResolve
1.如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域则都必须声明为transient
2.readResolve的可访问性很重要,私有,子类不能用,包级私有,包级的子类可用,受保护和公有的,子类没有覆盖,
子类反序列化时会产生一个父类,导致ClassCastException
3.使用枚举,java保证除了声明的常量之外,不会有其他实例,除非攻击者恶意的使用了取得特权的方法,
AccessibleObject.setAccessible,如果攻击者可以这样做,那么他可以执行任何本地的代码了,这是很危险的

第九十条,考虑用序列化代理替代序列化实例
1.当你发现自己必须在一个不能被客户端扩展的类上编写readObject或者writeObject方法时,就应该考虑使用序列化代理
模式,要想稳健地将带有重要约束条件的对象序列化时,这种模式可能是最容易的反方
2.首先,为可序列化的类设计一个私有的静态嵌套类,精确地表示外围类的实例的逻辑状态,这个嵌套类被称为
序列化代理类,它应该有一个单独的构造器,其参数类型就是外围类,这个构造器只从他的参数中复制数据,它
不需要进行任何一致性检查和保护性拷贝,外围类和序列化代理都需要实现serializable,可序列化的类有readResolve
方法,里面直接通过构造器和静态工厂来产生外围类
3.private Object writeReplace(){ return new 序列化代理类();},这个可以让序列化系统产生一个序列化代理类替换外围实例
4.外围类的readObject方法抛出异常即可

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容