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 writeObject()
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 that the accessibility of the class constructor (if any); otherwise it should be reduced to private
.
...
This noncompliant code example shows a class Ser
, which has a private
constructor. This means that code external to the class should be unable to create its instance. The class implements java.io.Serializable
and defines the readObject()
and writeObject()
methods. The accessibility of both the methods is public
which allows untrusted code to obtain the reconstituted object (in case of readObject()
) and write to the stream (in case of writeObject()
).
Code Block | ||
---|---|---|
| ||
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(); } } |
...
This compliant solution declares the readObject()
and writeObject()
methods private
and non-static to limit their accessibility.
Code Block | ||
---|---|---|
| ||
private void writeObject(final ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); } private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); } |
This also prevents malicious subclassing.
Risk Assessment
Failure to limit the accessibility of the readObject()
and writeObject()
methods can leave code vulnerable to untrusted invocations.
...