5.2 Language-specific formats — and why not to use them
java.io.Serializable, Python pickle, Ruby Marshal, Kryo for Java.
java.io.Serializable, Python pickle, Ruby Marshal, Kryo for Java.
Convenient — in-memory objects saved and restored with minimal code. But four deep problems:
| Problem | Consequence |
|---|---|
| Tied to one programming language | Reading in another language is difficult. You commit to your current language for potentially a long time and preclude integrating with other organizations' systems |
| Decoding must instantiate arbitrary classes | A frequent source of security problems. If an attacker can get your application to decode an arbitrary byte sequence, they can instantiate arbitrary classes, which often allows remote code execution |
| Versioning is an afterthought | Built for quick-and-easy encoding; they neglect forward and backward compatibility |
| Efficiency is an afterthought | Java's built-in serialization is notorious for bad performance and bloated encoding |
Generally a bad idea for anything other than very transient purposes.
(In practice: "deserialization of untrusted data" is a top-10 vulnerability class — Java gadget chains, Python pickle.loads, PHP unserialize, Ruby YAML. If you take one operational rule from this section: never deserialize a language-native format from a source you don't control.)
5.1 Encoding and decoding
Programs work with data in (at least) two representations:
5.3 JSON, XML, CSV, and binary variants
Widely adopted: in OpenAPI specs, in schema registries (Confluent Schema Registry, Red Hat Apicurio), and in databases (PostgreSQL's pg_jsonschema, MongoDB's $jsonSchema validator…