rspec/rules/S1948/java/rule.adoc

128 lines
4.6 KiB
Plaintext

This rule raises an issue on a non-transient and non-serializable field within a serializable class, if said class does not have `writeObject` and `readObject` methods defined.
== Why is this an issue?
By contract, fields in a `Serializable` class must themselves be either `Serializable` or `transient`.
Even if the class is never explicitly serialized or deserialized, it is not safe to assume that this cannot happen.
For instance, under load, most J2EE application frameworks flush objects to disk.
An object that implements `Serializable` but contains non-transient, non-serializable data members (and thus violates the contract) could cause application crashes and open the door to attackers.
In general, a `Serializable` class is expected to fulfil its contract and not exhibit unexpected behaviour when an instance is serialized.
This rule raises an issue on:
* non-`Serializable` fields,
* collection fields when they are not `private` (because they could be assigned non-`Serializable` values externally),
* when a field is assigned a non-`Serializable` type within the class.
== How to fix it
Consider the following scenario.
[source,java,diff-id=1,diff-type=noncompliant]
----
public class Address {
...
}
public class Person implements Serializable {
private static final long serialVersionUID = 1905122041950251207L;
private String name;
private Address address; // Noncompliant, Address is not serializable
}
----
How to fix this issue depends on the application's needs. If the field's value should be preserved during serialization and deserialization, you may want to make the field's value serializable.
[source,java,diff-id=1,diff-type=compliant]
----
public class Address implements Serializable {
private static final long serialVersionUID = 2405172041950251807L;
...
}
public class Person implements Serializable {
private static final long serialVersionUID = 1905122041950251207L;
private String name;
private Address address; // Compliant, Address is serializable
}
----
If the field's value does not need to be preserved during serialization and deserialization, mark it as `transient`. The field will be ignored when the object is serialized. After deserialization, the field will be set to the default value corresponding to its type (e.g., `null` for object references).
[source,java,diff-id=1,diff-type=compliant]
----
public class Address {
...
}
public class Person implements Serializable {
private static final long serialVersionUID = 1905122041950251207L;
private String name;
private transient Address address; // Compliant, the field is transient
}
----
The alternative to making all members serializable or `transient` is to implement special methods which take on the responsibility of properly serializing and de-serializing the object `writeObject` and `readObject`. These methods can be used to properly (de-)serialize an object, even though it contains fields that are not transient or serializable. Hence, this rule does not raise issues on fields of classes which implement these methods.
[source,java,diff-id=1,diff-type=compliant]
----
public class Address {
...
}
public class Person implements Serializable {
private static final long serialVersionUID = 1905122041950251207L;
private String name;
private Address address; // Compliant, writeObject and readObject handle this field
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
// Appropriate serialization logic here
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
// Appropriate deserialization logic here
}
}
----
== Resources
* https://cwe.mitre.org/data/definitions/594[Saving Unserializable Objects to Disk - MITRE, CWE-594]
* https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html[Interface Serializable - Java SE 11 API Documentation]
* https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html[Interface Serializable - Java SE 17 API Documentation]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
Make "xxx" transient or serializable.
'''
== Comments And Links
(visible only on this page)
=== is duplicated by: S2058
=== on 21 Dec 2016, 14:16:57 Tibor Blenessy wrote:
There is a limitation to the rule discussed in
https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/sonarqube/ofykNf_8tso/mvwWvM6JBAAJ
The pattern of throwing NotSerializableException is described here \http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html
endif::env-github,rspecator-view[]