Serialization can be used maliciously. Examples include using serialization to maliciously violate the intended invariants of a class. Deserialization is equivalent to object construction; consequently all invariants enforced during object construction must also be enforced during deserialization. The default serialized form lacks any enforcement of class invariants; consequently, it is forbidden to use the default serialized form for any class with implementation-defined invariants.
Noncompliant Code Example
In this noncompliant code example (based on [[Bloch 2005]]), a class with singleton semantics uses the default serialized form, which fails to enforce any implementation-defined invariants. Consequently, the malicious code can create a second instance even though the class should have only a single instance. For purposes of this example, we assume that the class contains only nonsensitive data.
public class SingletonClass extends Exception { public static final SingletonClass INSTANCE = new SingletonClass(); private SingletonClass() { // Perform security checks and parameter validation } protected int printData() { int data = 1000; return data; } } class Malicious { public static void main(String[] args) { SingletonClass sc = (SingletonClass) deepCopy(SingletonClass.INSTANCE); System.out.println(sc == SingletonClass.INSTANCE); // Prints false; indicates new instance System.out.println("Balance = " + sc.printData()); } // This method should not be used in production quality code static public Object deepCopy(Object obj) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ObjectOutputStream(bos).writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray()); return new ObjectInputStream(bin).readObject(); } catch (Exception e) { throw new IllegalArgumentException(e); } } }
Compliant Solution
This compliant solution adds a custom readResolve()
method that replaces the deserialized instance with a reference to the appropriate singleton from the current execution. More complicated cases may also require custom writeObject()
or readObject()
methods in addition to (or instead of) the custom readResolve()
method. Note that the custom serialization methods must be declared final
to prevent a malicious subclass from overriding them.
class SingletonClass extends Exception { // ... private final Object readResolve() throws NotSerializableException { return INSTANCE; } }
Risk Assessment
Serializing objects with implementation defined characteristics can corrupt the state of the object.
Guideline |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
SER08-J |
low |
probable |
high |
P2 |
L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this guideline on the CERT website.
Bibliography
[[API 2006]] Class Object
, Class Hashtable
[[Bloch 2008]] Item 75: "Consider using a custom serialized form"
SER07-J. Make defensive copies of private mutable components during deserialization 16. Serialization (SER) SER09-J. Minimize privileges before deserializing from a privileged context