A A Serializable
class can overload the Serializable
.readObject()
method, which is called when an object of that class is being deserialized. Both this method and the method the readResolve()
must treat the serialized data as potentially malicious and must method should refrain from performing potentially dangerous operations, unless the programmer has expressly indicated for the particular deserialization at hand, that the class should be permitted to perform potentially dangerous operations. .
A class that performs dangerous operations in the constructor must not be Serializable
. This is because SER07-J. Do not use the default serialized form for classes with implementation-defined invariants would require that its readObject()
method perform the same dangerous operation as the constructor. As an alternative, such a class could be Serializable
if readObject()
always throws an exception.
This guideline is related to rule SER12-J. Prevent deserialization of untrusted dataThis rule complements rule SER12-J. Prevent deserialization of untrusted classes. Whereas SER12-J requires the programmer to ensure the absence of classes that might perform dangerous operations when deserialized by validating data before deserializing it, SER13-J requires that all serializable classes refrain, by default, from performing dangerous operations during deserialization. SER12-J and SER13-J both guard against the same class of deserialization vulnerabilities. Theoretically, a given system is secure against this class of vulnerabilities if either (1) all deployed code on that system follows SER12-J or (2) all deployed code on that system follows SER13-J. However, because much existing code violates these rules, the CERT Coding Standard takes the "belt and suspenders" approach and requires compliant code to follow both rules.
Non-Compliant Code Example
The class OpenedFile
in In the following non-compliant code example opens , the class OpenedFile
opens a file during deserialization. Operating systems typically impose a limit on the number of open file handles per process; . Usually, this limit typically is not large (e.g., 1024). Consequently, deserializing a list of OpenedFile
objects can consume all file handles available to the process and consequently cause the program to malfunction if it attempts to open another file before the deserialized OpenedFile
objects get garbage-collected.
Code Block | ||||
---|---|---|---|---|
| ||||
import java.io.*; class OpenedFile implements Serializable { public String filename; public BufferedReader reader; public OpenedFile(String _filename) throws FileNotFoundException { this.filename = _filename; init(); } private void init() throws FileNotFoundException { reader = new BufferedReader(new FileReader(filename)); } private void writeObject(ObjectOutputStream out) throws IOException { out.writeUTF(filename); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { filename = in.readUTF(); init(); } } |
Compliant Solution
In this compliant solution, potentially dangerous operations are moved outside of deserialization, the readObject()
method throws an exception unless the potentially dangerous class is whitelistedand users of the class are required to make a separate call to init()
after deserializing.
Code Block | ||||
---|---|---|---|---|
| ||||
import java.io.*; import java.lang.reflect.*; class OpenedFile implements Serializable { public String filename; public BufferedReader reader; boolean isInitialized; public OpenedFile(String _filename) throws FileNotFoundException { this.filename = _filename; init()isInitialized = false; } private public void init() throws FileNotFoundException { reader = new BufferedReader(new FileReader(filename)); isInitialized = true; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeUTF(filename); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { boolean isWhitelistedfilename = falsein.readUTF(); try { Object whitelist = in.getClass().getDeclaredField("whitelist").get(in); Method contains = whitelist.getClass().getMethod("contains", new Class[]{Object.class}); isWhitelisted = contains.invoke(whitelist, this.getClass().getName()).equals(Boolean.TRUE); } catch (ReflectiveOperationException e) {} if (!isWhitelisted) { throw new SecurityException("Attempted to deserialize unexpected class."); } filename = in.readUTF(); init(); } } |
Risk Assessment
isInitialized = false;
}
} |
Compliant Solution
In this compliant solution, we assume that OpenedFile
must be Serializable
because it inherits from a serializable superclass. Because OpenedFile
must perform dangerous operations in the constructor, it intentionally forbids deserialization by throwing an exception in readObject()
.
Code Block | ||||
---|---|---|---|---|
| ||||
import java.io.*;
class Unchangeable implements Serializable {
// ...
}
class OpenedFile extends Unchangeable { // Serializable, unfortunately
String filename;
BufferedReader reader;
boolean isInitialized;
public OpenedFile(String filename) {
this.filename = filename;
isInitialized = false;
}
public void init() throws FileNotFoundException {
reader = new BufferedReader(new FileReader(filename));
isInitialized = true;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeUTF(filename);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new NotSerializableException(OpenedFile.getClass().getName());
}
} |
Related Vulnerabilities
CERT Vulnerability #576313 describes a family of exploitable vulnerabilities that arise from violating this rule.
Risk Assessment
The severity of violations of this rule depend on the nature of the potentially dangerous operations performed. If only mildly dangerous operations are performed, the risk might be limited to denial-of-service (DoS) attacks. At the other extreme, remote code execution is possible if attacker-supplied input is supplied to methods such as Runtime.exec
(either directly or via reflection).
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SER13SEC58-J | High | Likely | High | P9 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Useful for developing exploits that detect violation of this rule |
Related Guidelines
Bibliography