Every serializable class that has private mutable instance variables must defensively copy them in the readObject() method. An attacker can tamper with the serialized form of such a class, appending extra references to the byte stream. When deserialized, this byte stream could allow the creation of a class instance whose internal variable references are controlled by the attacker. Consequently, this allows the class instance of the container class to can mutate and violate its class invariants.
This rule is an instance of OBJ06-J. Defensively copy mutable inputs and mutable internal components. Whereas that rule , which applies to constructors and to other methods that accept untrusted mutable arguments, this . This rule applies the same principle to deserialized mutable fields.
...
This noncompliant code example fails to defensively copy the mutable Date object date. An attacker might be able to create an instance of MutableSer whose date object contains a nefarious subclass of Date and whose methods can perform actions specified by an attacker. Any code that depends on the immutability of the subobject is vulnerable.
| Code Block | ||
|---|---|---|
| ||
class MutableSer implements Serializable {
private static final Date epoch = new Date(0);
private Date date = null; // Mutable component
public MutableSer(Date d){
date = new Date(d.getTime()); // Constructor performs defensive copying
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
// Perform validation if necessary
}
}
|
...
This compliant solution creates a defensive copy of the mutable Date object date in the readObject() method. Note the use of field-by-field input and validation of incoming fields. Additionally, note that this compliant solution is insufficient to protect sensitive data (see rule SER03-J. Do not serialize unencrypted , sensitive data for additional information).
| Code Block | ||
|---|---|---|
| ||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField fields = ois.readFields(); Date inDate = (Date) fields.getFieldget("date", epoch); // Defensively copy the mutable component date = new Date(inDate.getTime()); // Perform validation if necessary } |
...
There is no need to copy immutable subobjects. Also, avoid using the subobject's {{clone()}} method because it can be overridden when the subobject's class is non-not final and produces only a shallow copy. The subobjects ({{date}}) themselves must be non-final so that defensive copying can occur. It is also inadvisable to use the {{writeUnshared()}} and {{readUnshared()}} methods as an alternative \[[Bloch 2008|AA. Bibliography#Bloch 08]\references to the subobjects themselves must be nonfinal so that defensive copying can occur. It is also inadvisable to use the writeUnshared() and readUnshared() methods as an alternative [Bloch 2008].
Risk Assessment
Failure to defensively copy mutable components during deserialization can violate the immutability contract of an object.
Rule | Severity | Likelihood |
|---|
Detectable | Repairable | Priority | Level |
|---|---|---|---|
SER06-J |
low
probable
medium
P4
Low | Probable | Yes | Yes | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| CodeSonar |
| JAVA.CLASS.SER.ND | Serialization Not Disabled (Java) | ||||||
| Coverity | 7.5 | UNSAFE_DESERIALIZATION | Implemented |
Related Guidelines
Bibliography
...
[API |
AA. Bibliography#API 06]]
]]></ac:plain-text-body></ac:structured-macro>
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5d8e2837-c5f8-475a-98e1-ba52e56a2c69"><ac:plain-text-body><![CDATA[
[[Bloch 2008
AA. Bibliography#Bloch 08]]
Item 76: "Write readObject methods defensively"
]]></ac:plain-text-body></ac:structured-macro>
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="3c1f02e3-e3f1-48e1-b2d5-1ff38e3cb78d"><ac:plain-text-body><![CDATA[
[[Sun 2006
AA. Bibliography#Sun 06]]
"Serialization specification: A.6 Guarding Unshared Deserialized Objects"
]]></ac:plain-text-body></ac:structured-macro>
2014] | |
Item 76, "Write | |
[Sun 2006] | Serialization Specification, A.6, Guarding Unshared Deserialized Objects |
...
13. Serialization (SER) SER07-J. Do not use the default serialized form for implementation-defined invariants