You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 30 Next »

According to the Java API [[API 2006]] class Object, method hashcode() documentation

Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

Consequently, the hashcode of an object need not remain consistent across different executions of the application. Similarly, if an object is serialized, its hashcode may not stay consistent with the original value. This introduces several hurdles; for example, upon deserialization of a hashtable, it is impossible to retrieve the contained objects because the corresponding key values may have changed.

Noncompliant Code Example

This noncompliant code example uses the Key class as the key index for the Hashtable. According to the Java API [[API 2006]] class Hashtable documentation

To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.

This example follows the above advice but serialization is still at the mercy of the implementation of the hashcode() method. It is not required to produce a key value (hashcode) that is consistent across different executions of the program or during (de)serialization. Consequently, using the default serialized form of the hashtable is inappropriate. In this noncompliant code example, it is not possible to retrieve the value of the object using the original key after deserialization.

class Key implements Serializable {
  // Overrides hashcode and equals methods
}

class HashSer {
  public static void main(String[] args) throws IOException, ClassNotFoundException {
    Hashtable<Key,String> ht = new Hashtable<Key, String>();
    Key key = new Key();
    ht.put(key, "Value");
    System.out.println("Entry: " + ht.get(key)); // Retrieve using the key, works
	 
    // Serialize the Hashtable object
    FileOutputStream fos = new FileOutputStream("hashdata.ser");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(ht);
    oos.close();
	 
    // Deserialize the Hashtable object
    FileInputStream fis = new FileInputStream("hashdata.ser");
    ObjectInputStream ois = new ObjectInputStream(fis);
    Hashtable<Key, String> ht_in = (Hashtable<Key, String>)(ois.readObject());
    ois.close();
	 
    if(ht_in.contains("Value")) // Check if the object actually exists in the Hashtable
      System.out.println("Value was found in deserialized object.");
	 
    if (ht_in.get(key) == null) // Gets printed
      System.out.println("Object was not found when retrieved using the key.");	 
  }
}

Compliant Solution

This compliant solution changes the type of the key value so that it remains consistent across different runs of the program and a multitude of JVMs. This can be achieved by using an Integer object, for example, to hold the key values.

class HashSer {
  public static void main(String[] args) throws IOException, ClassNotFoundException {
    Hashtable<Integer, String> ht = new Hashtable<Integer, String>();
    ht.put(new Integer(1), "Value");
    System.out.println("Entry: " + ht.get(1)); // Retrieve using the key
	 
    // Serialize the Hashtable object
    FileOutputStream fos = new FileOutputStream("hashdata.ser");
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(ht);
    oos.close();
	 
    // Deserialize the Hashtable object
    FileInputStream fis = new FileInputStream("hashdata.ser");
    ObjectInputStream ois = new ObjectInputStream(fis);
    Hashtable<Integer, String> ht_in = (Hashtable<Integer, String>)(ois.readObject());
    ois.close();
	 
    if(ht_in.contains("Value")) // Check if the object actually exists in the Hashtable
      System.out.println("Value was found in deserialized object.");
	 
    if (ht_in.get(1) == null)  // Does not get printed
      System.out.println("Object was not found when retrieved using the key.");	 
  }
}

This problem can also be avoided by overriding the equals() and the hashcode() method in the Key class, though it is best to avoid serializing hash tables that are known to use implementation defined parameters.

Risk Assessment

Serializing objects with implementation defined characteristics can corrupt the state of the object.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

SER08-J

low

probable

high

P2

L3

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this guideline on the CERT website.

Bibliography

[[API 2006]] Class Object, Class Hashtable
[[Bloch 2008]] Item 75: "Consider using a custom serialized form"


SER07-J. Make defensive copies of private mutable components      16. Serialization (SER)      SER09-J. Do not deserialize from a privileged context

  • No labels