Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: fixed intro, NCE

The serialization and deserialization mechanism must respect the accessibility of the implementing class. Untrusted code should not be able to write to the stream using the writeObject() method nor should it be able to create an instance of the object by calling the readObject() method. The accessibility of these methods must match with the accessibility of the class constructor (if any); otherwise it should be reduced to private.

Even when hostile code does not have access to the serializable class's members, serialization may fail to work as expected. The ObjectInputStream.readObject() and ObjectOutputStream.writeObject() methods are declared final and cannot be overridden. The custom form of serialization involves a method that allows the JVM to detect private implementations of the two methods in the serializable class. If the accessibility of the two methods is not private, the default serialization form takes effect. This can be insecure from many standpoints, for instance, input validation checks installed in the custom serialized form may be bypassed.

Noncompliant Code Example

...

Code Block
bgColor#FFcccc
public class Ser implements Serializable {
  private static 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, omission of the static keyword does not make this example secure because the two methods will not be detected by the JVM, 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.

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

This Reducing the accessibility also prevents malicious subclassingoverriding of the two methods.

Risk Assessment

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

...