Object serialization allows saving an object's state as a sequence of bytes and its reconstitution at a later time. The primary application of serialization is in Java Remote Method Invocation (RMI) wherein objects must be packed (marshalled), exchanged between distributed virtual machines, and unpacked (unmarshalled). It also finds extensive use in Java Beans.
After a serializable class is exported, attempts to refactor its code can become burdensome. Specifically, the old serialized form (encoded representation) must be continually supported as it is part of the published API. This can be troublesome from a security perspective, as it not only promotes dead code but also burdens the provider who has to eternally maintain the existing codebase.
When a class implements Serializable
and does not override its functionality, it is said to be using the default serialized form. If the class changes in the future, any byte stream produced by users of the old class will not be compatible with the new implementation. Moving to a custom serialized form releases the implementer from the trap of having to maintain the original serialized form as well as the corresponding version of the class.
Noncompliant Code Example
This noncompliant code example implements a GameWeapon
class with a serializable field called noOfWeapons
, and uses the default serialization form. Any changes to the internal representation of the class can break the existing serialized form.
class GameWeapon implements Serializable { int noOfWeapons = 10; public String toString() { return String.valueOf(noOfWeapons); } }
Compliant Solution
Ideally, implement Serializable
only when the class is not expected to evolve frequently. One way to maintain the original serialized form, at the same time allowing the class to evolve is to use custom serialization with the help of serialPersistentFields
. The static
and transient
fields allow you to specify what should not be serialized whereas the serialPersistentFields
field specifies what should be serialized. It also relieves the class from defining the serializable field within the class implementation, decoupling the current implementation from the logic. New fields can easily be added without breaking compatibility across releases.
class WeaponStore implements Serializable { int noOfWeapons = 10; // total number of weapons } public class GameWeapon implements Serializable { WeaponStore ws = new WeaponStore(); private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("ws", WeaponStore.class)}; private void readObject(ObjectInputStream ois) throws IOException { try { ObjectInputStream.GetField gf = ois.readFields(); this.ws = (WeaponStore) gf.get("ws", ws); } catch (ClassNotFoundException e) { /* call handler */ } } private void writeObject(ObjectOutputStream oos) throws IOException { ObjectOutputStream.PutField pf = oos.putFields(); pf.put("ws", ws); oos.writeFields(); } public String toString() { return String.valueOf(ws); } }
Notably, according to the Serialization Specification [[Sun 06]]:
Inner classes can only contain
final static
fields that are initialized to constants or expressions built up from constants. Consequently, it is not possible to setserialPersistentFields
for an inner class (though it is possible to set it forstatic
member classes).
Finally, serialization is easy to get wrong and must consequently be carefully designed.
Risk Assessment
Failure to provide a consistent serialization mechanism across releases can limit the extensibility of classes. If classes are extended, it is possible for compatibility issues to get introduced.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
SER00- J |
low |
probable |
high |
P2 |
L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[[API 06]]
[[Sun 06]] "Serialization specification", "1.5 Defining Serializable Fields for a Class" and "1.7 Accessing Serializable Fields of a Class"
[[Bloch 08]] Item 74: "Implement serialization judiciously"
[[Harold 06]] 13.7.5. serialPersistentFields
[[MITRE 09]] CWE ID 589 "Call to Non-ubiquitous API"
13. Serialization (SER) 13. Serialization (SER) SER01-J. Avoid memory and resource leaks during serialization