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, the class instance can mutate and violate its class invariants.
This rule is an instance of rule OBJ06-J. Defensively copy mutable inputs and mutable internal components, which applies to constructors and to other methods that accept untrusted mutable arguments, whereas 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 nonfinal not final and produces only a shallow copy. The 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|AA. Bibliography#Bloch 08]\].
Risk Assessment
Failure to defensively copy mutable components during deserialization can violate the immutability contract of an object.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SER06-J |
Low |
Probable |
Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
CodeSonar |
| JAVA.CLASS.SER.ND | Serialization Not Disabled (Java) | ||||||
Coverity | 7.5 | UNSAFE_DESERIALIZATION | Implemented |
Related Guidelines
Bibliography
Untrusted Data |
Bibliography
[API 2014] | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2dbda617-98c7-4b8f-a05c-1f79f6778abe"><ac:plain-text-body><![CDATA[
[[API 2006
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="ef323ca7-bf38-4e94-970f-af1ad6fd669d"><ac:plain-text-body><![CDATA[
[[Bloch 2008
] | Item 76, |
readObject
methods defensively "Write |
[Sun 2006] |
]]></ac:plain-text-body></ac:structured-macro>
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="742d1368-febc-4f52-a7d0-34089f7b0854"><ac:plain-text-body><![CDATA[
[[Sun 2006
Serialization Specification, A.6, Guarding Unshared Deserialized Objects |
]]></ac:plain-text-body></ac:structured-macro>
...
13. Serialization (SER) SER07-J. Do not use the default serialized form for implementation-defined invariants