Class SafeObjectInputStream

java.lang.Object
java.io.InputStream
java.io.ObjectInputStream
google.registry.util.SafeObjectInputStream
All Implemented Interfaces:
Closeable, DataInput, ObjectInput, ObjectStreamConstants, AutoCloseable

public final class SafeObjectInputStream extends ObjectInputStream
Safely deserializes Nomulus http request parameters.

Serialized Java objects may be passed between Nomulus components that hold different credentials. Deserialization of such objects should be protected against attacks through compromised accounts.

This class protects against three types of attacks by restricting the classes used for serialization:

  • Remote code execution by referencing bad classes in compromised jars. When a class with malicious code in the static initialization block or the deserialization code path (e.g., the readObject method) is deserialized, such code will be executed. For Nomulus, this risk comes from third-party dependencies. To counter this risk, this class only allows Nomulus (google.registry.**) classes and specific core Java classes, and forbid others including third-party dependencies. (As a side note, this class does not use allow lists for Nomulus or third-party classes because it is infeasible in practice. Super classes of the instance being deserialized must be resolved, and therefore must be on the allow list; same for the field types of the instance. The allow list for the Joda DateTime class alone would have more than 10 classes. Generated classes, e.g., by AutoValue, present another problem: their real names are not meant to be a concern to the user).
  • CPU-targeting denial-of-service attacks. Containers and arrays may be used to construct object graphs that require enormous amount of computation during deserialization and/or during invocations of methods such as hashCode or equals, taking minutes or even hours to complete. See here for an example of such object graphs. To counter this risk, this class forbids lists, maps, and arrays for deserialization.
  • Memory-targeting denial-of-service attacks. By forbidding container and arrays, this class also prevents some memory-targeting attacks, e.g., using wire format that claims to be an array of a huge size, causing the JVM to preallocate excessive amount of memory and triggering the OutOfMemoryError. This is actually a small risk for Nomulus, since the impact of each error is limited to a single (spurious) request.

Nomulus classes with fields of array, container, or third-party Java types must implement their own serialization/deserialization methods to be safely deserialized. For the common use case of passing a collection of `safe` objects, SafeSerializationUtils.serializeCollection(java.util.Collection<?>) and SafeSerializationUtils.safeDeserializeCollection(java.lang.Class<T>, byte[]) may be used.