为什么尽量不要实现Serializable接口?如何做到序列化安全?
2271
2022.07.10
2022.07.10
发布于 未知归属地

什么是序列化

  • 序列化:就是把对象转换成字节。
  • 反序列化:把字节数据转换成对象。

序列化场景:

  • 对象网络传输
  • 对象保存到文件中

序列化注意事项

父类实现了Serializable,子类不需要实现Serializable

相关注意事项
a)序列化时,只对对象的状态进行保存,而不管对象的方法;
b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

序列化对象中的HashMap、HashSet或HashTable等集合不能包含对象自身的引用

class Super implements Serializable {
    private static final long serialVersionUID = -2589766491699675794L;
    final Set<Super> set = new HashSet<>();
    }
    final class Sub extends Super { 
        .....
        set.add(this) // 违反规则
    }

尽量不要实现Serializable接口

建议除非必须使用的第三方接口要求必须实现Serializable接口,否则不建议使用的原因包括:()
A: 序列化对外公开了对象的物理实现
B: 序列化容易使一个类对其最初的内部表示产生依赖
C: 编写正确的反序列化代码有很大的挑战
D: 序列化增大了安全风险
E: 序列化增加了测试的难度
答案解析 ABCDE
  • 实现Serializable接口的可序列化类应该显式声明serialVersionUID。
  • 如果可序列化类未显式声明serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认serialVersionUID值,如“Java™ 对象序列化规范”中所述。
  • 但是,强烈建议所有可序列化类都显式声明serialVersionUID值,原因是计算默认的serialVersionUID对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的InvalidClassException 。
  • 因此,为保证serialVersionUID值跨不同java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID值。
下面对Java反序列化的描述正确的是: ()
A. jdk提供的序列化操作,会将Java对象序列化二进制流,可以有效防止信息泄露或恶意篡改
B. Java的反序列化操作,可以绕过对象构造函数的执行
C. 对象序列化后,即使包含敏感数据也不会产生风险
D. Java反序列化时,目标class与预期class不一致时,会导致类型转换错误,所以即使反序列化不可信数据也不会有安全风险
答案解析 B
对于不安全反序列化漏洞的防护描述错误的是: ()
A. XMLDecoder是jdk原生类,提供了xml的反序列化操作,所以相对Xstream,更推荐使用XMLDecoder进行xml数据的反序列化操作
B. 使用jdk原生api进行反序列化操作,涉及不可信数据时,可以重载ObjectInputStream的resolveClass()方法,在该方法中对目标class进行白名单校验
C. 对不可信的XML数据进行反序列化操作,推荐使用XStream实现,该组件支持白名单检查,新版本也提供了默认安全校验机制
D. 对不可信的json数据进行反序列化操作,可通过禁止开启type功能进行防护
答案解析A
关于序列化说法不正确的是 ()
A. 序列化只能保存对象的非静态成员交量,不能保存任何的成员方法和静态的成员变量
B. transient关键字的作用是:阻止实例中那些用此关键字声明的变量持久化
C. 当一个父类实现序列化,子类若要实现序列化,需要显式实现Serializable接口
D. 一个子类实现了Serializable接口,它的父类都没有实现Serializable接口,要想将父类对象也序列化,就需要让父类也实现Serializable接口
答案解析 c
以下说法正确的是:()
A、不要在代码中硬编码"\n""\r"作为换行符号,建议使用System.lineSeparator()方法获取运行时环境的换行符
B、编码时尽量依赖平台默认的字符编码方式
CString类的toUpperCase()toLowerCase()方法、format()方法,建议使用默认的编码模式进行转换
D、使用java.nio.charset中的类编码解码字符集
答案解析AD

序列化安全

防止未加密的敏感数据被序列的方法有

  • 使用transient定义敏感数据
  • 使用serialPersistentFields定义非敏感数据
  • 重新定义Serializable接口的 writeObject()、writeReplace()、writeExternal()这些函数,不将包含敏感信息的字段写到序列化字节流中。
  • 在序列化与反序列化涉及的 writeObject()和readObject()方法中使用安全管理器
评论 (0)