Versions Compared

Key

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

It is often possible for Java code to deserialize data that comes from an untrusted source; however this is forbidden by rule SER12-J. Prevent deserialization of untrusted classes.  A Serializable class can overload the readObject() method, which is called when an object of that class is being deserialized.   This method (as well as similar methods such as  Both this method and the readResolve() and readObjectNoData()) should treat the serialized data as potentially malicious. These methods should not perform dangerous operations, nor should they set the stage for such operations to be performed later in the deserialization process.  If it is convenient for a serializable class to perform operations with potentially dangerous side effects during deserialization, it should require that the programmer expressly whitelist method should refrain from performing 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 data.

Non-Compliant Code Example

The class OpenedFile in the below noncompliant example opens 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, and this limit is typically is not very large (e.g., 1024).  Consequently, deserializing a list of OpenedFile objects can exhaust consume all file handles available to the process 's available file handles 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() {
        trythrows FileNotFoundException {
            reader = new BufferedReader(new FileReader(filename));
        } catch (FileNotFoundException e) { }
    }
    
    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 the below this compliant solution, the readObject method throws an exception unless the potentially dangerous class is whitelistedoperations 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.*;
 
interface Whitelist {class OpenedFile implements Serializable {
  String filename;
  BufferedReader reader;
 public boolean has(String className)isInitialized;
}
class  WhitelistedObjectInputStreampublic extends ObjectInputStreamOpenedFile(String filename) {
    this.filename Whitelist= whitelistfilename;
    isInitialized = false;
 }

  public publicvoid WhitelistedObjectInputStreaminit(InputStream inputStream) throws IOExceptionFileNotFoundException {
    reader = new BufferedReader(new superFileReader(inputStreamfilename));
    isInitialized = true;
 }
     
  publicprivate void setWhitelistwriteObject(WhitelistObjectOutputStream wlout) throws IOException {
    out.writeUTF(filename);
  }

  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    whitelistfilename = wlin.readUTF();
    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
bgColor#ccccff
languagejava
import java.io.*;
 
class OpenedFileUnchangeable implements Serializable {
  // ...
}
class OpenedFile extends Unchangeable { // Serializable, unfortunately
 public String filename;
    public BufferedReader reader;
  boolean isInitialized;

  public OpenedFile(String _filename) {
        this.filename = _filename;
    isInitialized =   init()false;
     }

    private public void init() {
        trythrows FileNotFoundException {
            reader = new BufferedReader(new FileReader(filename));
    isInitialized    } catch (FileNotFoundException e) { }
    }
= true;
 }
     
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeUTF(filename);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    throw new   if (!(in instanceof WhitelistedObjectInputStream) || 
            !((WhitelistedObjectInputStream) in).whitelist.has(thisNotSerializableException(OpenedFile.getClass().getName())) 
        {
            throw new SecurityException("Attempted to deserialize unexpected class.");
        }
        filename = in.readUTF();
        init();
    }
}

...

);
 }
}

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 Added Image Added Image Added