Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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 whitelisted the class for the particular deserialization at hand.

This 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 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 both of these rules, the CERT Coding Standard takes the "belt and suspenders" approach and requires compliant code to follow both rules.

 

 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 dataFor the purposes of complying with SER13-J, it is permitted to to assume that, if an ObjectInputStream contains a whitelist, then control will pass to the readObject or readResolve method of a class C only if C is on the whitelist.  In other words, class C does not need to check that it appears on the whitelist; it only needs to check that a whitelist exists.  This eliminates the need to perform a redundant check against the whitelist, and it enables compatibility with a greater range of whitelist implementations.

Non-Compliant Code Example

In the following non-compliant code example, 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 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
bgColor#FFcccc
languagejava
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, the readObject() method throws an exception unless the deserialization is protected by a whitelist.  Note that this compliant solution for SER13-J is complementary to the compliant solution in SER12-J.  In the compliant solution for SER12-J, the source code location that invokes deserialization is modified to use a custom subclass of ObjectInputStream.  This subclass overrides the resolveClass() method to check whether class of the serialized object is whitelisted before that class's readObject() method gets called.  In contrast, in the compliant solution below for SER13-J, the presence of a whitelist is checked inside the readObject() method of the dangerous serializable class.potentially dangerous operations are moved outside of deserialization, and users of the class are required to make a separate call to init() after deserializing.

Code Block
bgColor#ccccff
languagejava
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 hasWhitelist = false;
    try {
        Object whitelistfilename = in.getClassreadUTF().getDeclaredField("whitelist").get(in);
    isInitialized    hasWhitelist = true;
    } catch (ReflectiveOperationException e) {}
    if (!hasWhitelist) {
      throw new SecurityException("Deserialization without a whitelist is disallowed for class " + 
                                  this.getClass().getName() + ".");
    }
    filename = in.readUTF();
    init();
  false;
 }
}

Compliant Solution

...

In this compliant solution, potentially dangerous operations are moved outside of deserialization, and users of the class are required to make a separate call to init() after deserializing.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
bgColor#ccccff
languagejava
import java.io.*;
 
class OpenedFileUnchangeable implements Serializable {
  // ...
}
class OpenedFile extends  publicUnchangeable { // Serializable, unfortunately
  String filename;
  public BufferedReader reader;
  boolean isInitialized;

  public OpenedFile(String _filename) throws FileNotFoundException {
    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 {
    filenamethrow = in.readUTF(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

LikelyHighP9L2

Automated Detection

Tool
Version
Checker
Description

ysoserial

  Useful for developing exploits that detect violation of this rule

Related Guidelines

MITRE CWE

CWE-502, Deserialization of Untrusted Data

Bibliography

Image Modified Image Modified Image Modified