知识卡片

语言特定序列化的三个深层问题

普通读书笔记卡

内容

许多编程语言内置了把内存对象直接编码成字节序列的能力(Java的Serializable、Ruby的 Marshal、Python的pickle),用起来非常方便,只需极少代码就能保存和恢复对象,但这类 方案有三个容易被忽视的深层问题。第一是语言锁定:这类编码通常与特定编程语言深度 绑定,其他语言很难读取,一旦用它存储或传输数据,就等于把这份数据和这门语言焊死在 一起,很难和用别的语言写的系统集成。第二是安全隐患:为了把字节序列还原成”相同 类型”的对象,解码过程往往需要具备”实例化任意类”的能力——这正是一类常见安全漏洞的 根源,如果攻击者能诱导应用程序解码一段精心构造的字节序列,就可能借此实例化任意类、 达成远程代码执行这样的严重后果。第三是版本控制和效率往往是事后才被考虑的:这类库 设计初衷是”快速方便地把对象存下来”,很少会认真设计前向/后向兼容性,因此模式变化后 经常直接读不了旧数据;效率同样常被忽视,Java内置序列化就因为性能糟糕、编码臃肿而 臭名昭著。综合这三点,除非只是临时使用(比如同一个短生命周期进程内部的缓存), 采用语言内置的序列化通常是个坏主意——它省下的开发时间往往会在跨语言集成、安全 加固、格式演进这些后续问题上加倍还回去。

参考来源

- 位置:《数据密集型应用系统设计》第四章《编码与演化》"语言特定的格式"(源文件: _epub-src/ch4_split_000.html) - 结论依据:原文列出语言特定编码的三个问题:与特定语言深度绑定难以跨语言集成、 解码需要实例化任意类因而成为安全问题来源、版本控制和效率通常是事后才考虑的, 并举Java内置序列化性能差为例,最终建议除非临时使用否则不宜采用,直接支撑本卡片 结论。 - 原始内容:这类编码通常与特定的编程语言深度绑定……为了恢复相同对象类型的数据, 解码过程需要实例化任意类的能力,这通常是安全问题的一个来源……在这些库中,数据 版本控制通常是事后才考虑的……因此,除非临时使用,采用语言内置编码通常是一个 坏主意。