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

Compare with Current View Page History

« Previous Version 35 Next »

The Java API [API 2006] for the Serializable inteface declares:

Classes that require special handling during the serialization and deserialization process must implement special methods with these exact signatures:

private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;

According to the Serialization Specification [[Sun 2006]], readResolve() and writeReplace() method documentation:

For Serializable and Externalizable classes, the readResolve method allows a class to replace/resolve the object read from the stream before it is returned to the caller. By implementing the readResolve method, a class can directly control the types and instances of its own instances being deserialized.

For Serializable and Externalizable classes, the writeReplace method allows a class of an object to nominate its own replacement in the stream before the object is written. By implementing the writeReplace method, a class can directly control the types and instances of its own instances being serialized.

It is possible to add any access-specifier to the readResolve() and writeReplace() methods. However, if they are declared private, extending classes cannot invoke or override them. Similarly, if either of these methods is declared static, extending classes cannot override the method, they can only hide it.

Deviating from these method signatures produces a method that will, in fact, not be invoked during object serialization or deserialization. Such a method will clearly not have the expected behavior. Such methods, especially if declared public, might be accessible to untrusted code.

Be aware that, unlike most interfaces, Serializable does not define the method signatures it requires. It cannot, because readObject() and writeObject() are private. Consequently, the Java compiler will not identify a deviant method signature.

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.

Noncompliant Code Example

This noncompliant code example declares the readResolve() and writeReplace() methods as private.

class Extendable implements Serializable {
  private Object readResolve() {
    // ...
  }

  private Object writeReplace() {
    // ...
  }
}

Noncompliant Code Example

This noncompliant code example declares the readResolve() and writeReplace() methods as static.

class Extendable implements Serializable {
  protected static Object readResolve() {
    // ...
  }

  protected static Object writeReplace() {
    // ...
  }
}

Compliant Solution

This compliant solution declares the two methods protected while eliminating the static keyword, so that subclasses can inherit them.

class Extendable implements Serializable {
  protected Object readResolve() {
    // ...
  }

  protected Object writeReplace() {
    // ...
  }
}

Risk Assessment

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

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SER01-J

high

likely

low

P27

L1

Related Vulnerabilities

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

Related Guidelines

MITRE CWE

CWE-502 "Deserialization of Untrusted Data"

Bibliography

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="57c0b9f4-ea57-4eec-9380-0baeabb89ed4"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

Serializable

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="60658b15-96e3-4c9e-9aa5-9e557379d3e1"><ac:plain-text-body><![CDATA[

[[Sun 2006

AA. Bibliography#Sun 06]]

"Serialization specification"

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="c46301ef-732b-43e1-9133-049dcc39bb2d"><ac:plain-text-body><![CDATA[

[[Ware 2008

AA. Bibliography#Ware 08]]

 

]]></ac:plain-text-body></ac:structured-macro>


SER00-J. Maintain serialization compatibility during class evolution      16. Serialization (SER)      SER02-J. Sign and seal sensitive objects before sending them outside a trust boundary

  • No labels