Working with Serialization
1. Implementing Serializable Interface
| Aspect | Detail |
|---|---|
| Marker interface | No methods to implement |
| Required | All non-transient fields must be Serializable |
| No-arg ctor | Required only in non-Serializable superclass |
2. Using ObjectOutputStream and ObjectInputStream
| API | Use |
|---|---|
writeObject(o) | Serialize |
readObject() | Deserialize (unchecked cast) |
writeUnshared / readUnshared | Avoid back-references |
| Order | Read in same order as written |
3. Understanding serialVersionUID
| Aspect | Detail |
|---|---|
| Declaration | private static final long serialVersionUID = 1L; |
| Purpose | Version compatibility check |
| Auto-generated | Compiler computes from class shape if absent |
| Recommendation | Always declare explicitly |
4. Customizing Serialization
| Hook | Use |
|---|---|
writeObject(ObjectOutputStream) | Custom write |
readObject(ObjectInputStream) | Custom read |
readObjectNoData() | For class evolution |
writeReplace / readResolve | Substitute object |
5. Using Externalizable Interface
| vs Serializable | Detail |
|---|---|
| Methods | writeExternal / readExternal |
| Control | Full byte-level control |
| No-arg ctor | Required (public) |
| Use | Performance-critical or compact format |
6. Handling transient Fields
| Use | Reason |
|---|---|
| Skip field | Not serialized |
| Restore in readObject | Recompute / re-init |
| Sensitive data | Passwords, sessions, derived caches |
7. Understanding Serialization Security Risks
| Risk | Mitigation |
|---|---|
| Gadget chains | Restrict deserializable classes |
| DoS | Hash-collision attacks; use input filters |
| RCE | Untrusted streams executing readObject |
| Best practice | Use JSON/Protobuf instead for external data |
8. Using SerialVersionUID Best Practices
| Practice | Reason |
|---|---|
| Always declare | Avoid surprise InvalidClassException |
| Bump on incompatible change | Reject old streams |
| Keep on compatible change | Add fields with sensible defaults |
Use serialver tool | Compute current value |
9. Implementing Custom Serialization Proxies
Example: Serialization proxy
public final class Period implements Serializable {
private final Date start, end;
private Object writeReplace() { return new SerProxy(this); }
private void readObject(ObjectInputStream s) throws InvalidObjectException {
throw new InvalidObjectException("Use proxy");
}
private static final class SerProxy implements Serializable {
private final Date start, end;
SerProxy(Period p) { this.start = p.start; this.end = p.end; }
private Object readResolve() { return new Period(start, end); }
}
}
| Benefit | Detail |
|---|---|
| Invariant safety | Reconstruct via real ctor |
| Immutability preserved | No reflection bypass |
10. Understanding Deserialization Vulnerabilities
| Vulnerability | Examples |
|---|---|
| Apache Commons Collections | InvokerTransformer chain (CVE-2015-7501) |
| Spring | Various RCE via deserialization gadgets |
| JNDI injection | Often combined with deser |
| Mitigation | Allow-list classes via ObjectInputFilter |
11. Using Serialization Filters (ObjectInputFilter)
| API | Use |
|---|---|
ObjectInputFilter.allowFilter(p, status) | Allow-list |
setObjectInputFilter(filter) | Per-stream |
| Global | jdk.serialFilter system property |
| Pattern | com.acme.*;!* (allow + reject all) |
| Factory | Per-context filter via FilterFactory |