...
Validating deserialized objects helps confirm that the object state is within defined limits and ensures that all transient
and static
fields have their default safe values. Fields that are declared final
and contain a constant value will contain the proper value after deserialization, rather than the default value. For example, the value of the field private transient final n = 42
after deserialization will be 42, rather than 0. Deserialization produces default values for all other cases.
Noncompliant Code Example (Singleton)
Wiki Markup |
---|
In this noncompliant code example (based on \[[Bloch 2005|AA. Bibliography#Bloch 05]\]), 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. |
Code Block | ||
---|---|---|
| ||
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.
...
Code Block | ||
---|---|---|
| ||
class SingletonClass extends Exception { // ... private final Object readResolve() throws NotSerializableException { return INSTANCE; } } |
Noncompliant Code Example
This noncompliant code example uses a custom defined readObject()
method, but fails to perform input validation after deserialization. The design of the system requires the maximum value of any lottery ticket to be 20,000; however, an attacker can manipulate the serialized array to generate a different number on deserialization.
Code Block | ||
---|---|---|
| ||
public class Lottery implements Serializable { private int ticket = 1; private SecureRandom draw = new SecureRandom(); public Lottery(int ticket) { this.ticket = (int) (Math.abs(ticket % 20000) + 1); } public int getTicket() { return this.ticket; } public int roll() { this.ticket = (int) ((Math.abs(draw.nextInt()) % 20000) + 1); return this.ticket; } public static void main(String[] args) { Lottery l = new Lottery(2); for(int i = 0; i < 10; i++) { l.roll(); System.out.println(l.getTicket()); } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); } } |
Compliant Solution
Any input validation performed in the constructors must also be implemented at all places where an object can be deserialized. This compliant solution performs field-by-field validation by reading all fields of the object using the readFields()
and getField()
methods. The value for each field must be fully validated before it is assigned to the object under construction. For more complicated invariants, this may require reading multiple field values into local variables to enable checks that depend on combinations of field values.
...
Note that this compliant solution is insufficient to protect sensitive data. See rule SER03-J. Prevent serialization of unencrypted, sensitive data for additional information.
Compliant Solution (transient
)
This compliant solution marks the fields as transient, so they are not serialized. The readObject()
initializes them using the roll()
method. This class need not be final, as its fields are private and cannot be tampered with by subclasses.
Code Block | ||
---|---|---|
| ||
public class Lottery implements Serializable { private transient int ticket = 1; private transient SecureRandom draw = new SecureRandom(); public Lottery(int ticket) { this.ticket = (int) (Math.abs(ticket % 20000) + 1); } public int getTicket() { return this.ticket; } public int roll() { this.ticket = (int) ((Math.abs(draw.nextInt()) % 20000) + 1); return this.ticket; } public static void main(String[] args) { Lottery l = new Lottery(2); for(int i = 0; i < 10; i++) { l.roll(); System.out.println(l.getTicket()); } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.draw = new SecureRandom(); roll(); } } |
Compliant Solution (non-serializable)
This compliant solution simply does not mark the Lottery
class serializable.
Code Block | ||
---|---|---|
| ||
public final class Lottery { // ... } |
Risk Assessment
Serializing objects with implementation defined characteristics can corrupt the state of the object.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SER08-J | medium | probable | high | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5747afae8d38a1d4-86c34546-49b24cc9-b14db8c1-dd7d46ccd6234ab29e83c054"><ac:plain-text-body><![CDATA[ | [[MITRE 2009 | AA. Bibliography#MITRE 09]] | [CWE ID 502 | http://cwe.mitre.org/data/definitions/502.html] "Deserialization of Untrusted Data" | ]]></ac:plain-text-body></ac:structured-macro> |
Bibliography
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="851329055ba3313b-d0025ad4-49b44c7c-9df488df-a51657837fedcb269f8d0e51"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] | Class | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="36ecf77c8a13fd52-f052de99-41a745fd-87afbcfe-0ebe789e4354cf4590f8bf25"><ac:plain-text-body><![CDATA[ | [[Bloch 2008 | AA. Bibliography#Bloch 08]] | Item 75: "Consider using a custom serialized form" | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="b3eedd44841ac30f-177b5c42-44d64f4e-87f5bbfb-1e5ef4466f9b55cbe3c75ede"><ac:plain-text-body><![CDATA[ | [[Greanier 2000 | AA. Bibliography#Greanier 00]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="22c6ffcf43a9e2d0-425ff2d0-48744d75-a10d8615-dc7ea2aaf936a7ecd3ad641a"><ac:plain-text-body><![CDATA[ | [[Harold 1999 | AA. Bibliography#Harold 99]] | Chapter 11: Object Serialization, Validation | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5c94309c5d111141-1f654d30-4bdb4948-b9fcb5a3-0c6d7cc21623c496872c32cc"><ac:plain-text-body><![CDATA[ | [[Hawtin 2008 | AA. Bibliography#Hawtin 08]] | Antipattern 8: Believing deserialisation is unrelated to construction | ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="adfd740c0c21802d-624d4d9a-47484729-a98d9081-3f5798d93e4653439f0e1e93"><ac:plain-text-body><![CDATA[ | [[SCG 2007 | AA. Bibliography#SCG 07]] | Guideline 5-2 View deserialization the same as object construction | ]]></ac:plain-text-body></ac:structured-macro> |
...