You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 24 Next »

The serialization and deserialization mechanism must respect the accessibility of the implementing class. Untrusted code must be prevented both from writing to the stream using the writeObject() method and also from creating an instance of an object by calling the readObject() method. For classes that have constructors, the accessibility of the readObject() and writeObject() methods must match the accessibility of the constructor; these methods must be declared private in all other cases.

Serialization may fail to work as expected even when hostile code lacks access to the serializable class's members. The ObjectInputStream.readObject() and ObjectOutputStream.writeObject() methods are declared final and cannot be overridden. The custom form of serialization involves a mechanism that allows the JVM to detect and use private implementations of the two methods in the serializable class. The JVM uses default serialization for all non-private ???. This can be insecure from many standpoints, for instance, input validation checks installed in the custom serialized form may be bypassed.

Noncompliant Code Example

This noncompliant code example shows a class Ser with a private constructor, indicating that code external to the class should be unable to create instances of it. The class implements java.io.Serializable and defines public readObject() and writeObject() methods. Consequently, untrusted code can obtain the reconstituted objects by using readObject(), and can write to the stream by using writeObject().

public class Ser implements Serializable {
  private final long serialVersionUID = 123456789;
  private Ser() {
    // initialize
  }
  public static void writeObject(final ObjectOutputStream stream) throws IOException {
    stream.defaultWriteObject();
  }
	
  public static void readObject(final ObjectInputStream stream) throws 
      IOException, ClassNotFoundException {
    stream.defaultReadObject();
  }
}

Similarly, omitting the static keyword is insufficient to make this example secure; the JVM will fail to detect the two methods, resulting in failure to use the custom serialized form.

Compliant Solution

This compliant solution declares the readObject() and writeObject() methods private and non-static to limit their accessibility.

private void writeObject(final ObjectOutputStream stream) throws IOException {
  stream.defaultWriteObject();
}
	
private void readObject(final ObjectInputStream stream) throws 
    IOException, ClassNotFoundException {
  stream.defaultReadObject();
}

Reducing the accessibility also prevents malicious overriding of the two methods.

Risk Assessment

Failure to limit the accessibility of the readObject() and writeObject() methods can leave code vulnerable to untrusted invocations.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

SER01-J

high

likely

low

P27

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this guideline on the CERT website.

Bibliography

[[Sun 2006]] "Serialization specification"
[[Ware 2008]]


SER00-J. Maintain serialization compatibility during class evolution      16. Serialization (SER)      SER02-J. Extendable classes should not declare readResolve() and writeReplace() private or static

  • No labels