Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: overhaul

Some classes contain data that must not be copied; these classes can be considered to be sensitive. If a class is not meant to be copied, then failing to define copy mechanisms, such as a copy constructor, is not sufficient to prevent copying.

Java's object cloning mechanism allows an attacker to manufacture new instances of a class by copying the memory images of existing objects rather than by executing its the class's constructor. Often this is not an acceptable way of creating new objects. An attacker can misuse the clone feature to manufacture multiple instances of a singleton class, create serious thread-safety issues by subclassing and cloning the subclass, bypass security checks within the constructor and violate the invariants of critical data.

Classes that have security checks in their constructors must beware of finalization attacks, as explained in OBJ04-J. Do not allow access to partially initialized objects.

Classes that are not sensitive, but maintain other invariants must be sensitive to the possibility of malicious subclasses accessing or manipulating their data, and possibly invalidating their invariants. See OBJ10-J. Provide mutable classes with copy functionality to allow passing instances to untrusted code safely for more information.

Noncompliant Code Example

This noncompliant code example derives some functional behavior from the implementation of the class java.lang.StringBuffer, prior to JDK v1.5. It defines class SensitiveClass which contains a character array used to internally hold a filename, along with a Boolean shared variable, initialized to false. This data is not meant to be copied; and SensitiveClass does not provide a copy constructor.

Code Block
bgColor#ffcccc
class SensitiveClass {
  private char[] filename;
  private Boolean shared = false;
 
  SensitiveClass(String filename) {
    this.filename = filename.toCharArray();
  }

  final void replace() {
    if (!shared)
      for(int i = 0; i < filename.length; i++) {
    	filename[i]= 'x';
    }
  }

  final String get() {
    if (!shared) {	
      shared = true;
      return String.valueOf(filename);
    } else {
      throw new IllegalStateException("Failed to get instance");
    }
  }
  
  final void printFilename() {
    System.out.println(String.valueOf(filename));
  }
}

...

It proceeds to create its own instance (ms1) and produces a second one (ms2), by cloning the first. It then obtains a new String filename object by invoking the get() method on the first instance. At this point, the shared flag is set to true. Because the second instance (ms2) does not have its shared flag set to true, it is possible to alter the first instance ms1 using the replace() method. This obviates any security efforts and severely violates the class's invariants.

Compliant Solution (final class)

The easiest way to prevent malicious subclasses is to declare SensitiveClass as final.

Code Block
bgColor#ccccff

final class SensitiveClass {
  // ...
}

Compliant Solution (final clone())

Sensitive classes should not implement the Cloneable interface, nor provide a copy constructor. Classes that extends extend from a superclass that implements Cloneable (and is consequently cloneable) should provide a clone() method that throws a CloneNotSupportedException. This exception must be caught and handled by the client code. A sensitive class that does not implement Cloneable must also follow this advice because it inherits the clone() method from Object. The class can prevent subclasses from being cloneable by defining a final clone() method that fails.

Code Block
bgColor#ccccff
final class SensitiveClass {
  // ...
  public final SensitiveClass Cloneclone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
  }
}

SensitiveClass must also be declared final to avoid malicious subclassing. This prevents an attacker from subclassing the sensitive class and creating copies of the subclass.

An alternative is to declare the clone() method final so that it cannot be overridden. The implementation must still throw a CloneNotSupportedExceptionThis does not prevent malicious subclasses, for more info on how to handle malicious subclasses, see OBJ10-J. Provide mutable classes with copy functionality to allow passing instances to untrusted code safely.

Risk Assessment

Failure to make sensitive classes noncloneable non-copyable can severely violate class invariants and provide malicious subclasses with the opportunity to exploit the code to create new instances of objects, even in the presence of the default security manager (in the absence of custom security checks).

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

OBJ02-J

medium

probable

medium

P8

L2

Related Vulnerabilities

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

Bibliography

Wiki Markup
\[[Mcgraw 1998|AA. Bibliography#Mcgraw 98]\] 
\[[MITRE 2009|AA. Bibliography#MITRE 09]\] [CWE ID 498|http://cwe.mitre.org/data/definitions/498.html] "Information Leak through Class Cloning", [CWE ID 491|http://cwe.mitre.org/data/definitions/491.html] "Public cloneable() Method Without Final (aka 'Object Hijack')"
\[[Wheeler 2003|AA. Bibliography#Wheeler 03]\] 10.6. Java 

...