Java's Object cloning mechanism can allow an attacker to manufacture new instances of classes that have been defined, without executing its constructorClasses containing private, confidential, or otherwise sensitive data are best not copied. If a class is not cloneable, the attacker can define a subclass, and make the subclass implement the java.lang.Cloneable interface. This lets an attacker create new instances of the class. The new instances of the class are made meant to be copied, then failing to define copy mechanisms, such as a copy constructor, is insufficient 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 ; though rather than by executing the class's constructor. Often, this is sometimes an acceptable unacceptable way of making a new object, it often is not.
Non Compliant Code
Consider the following class definition. Unless someone knows the secret password, objects cannot be created as the constructor for the class checks for the password stored in some password file.
creating new objects. An attacker can misuse the clone feature to manufacture multiple instances of a singleton class, create 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 OBJ11-J. Be wary of letting constructors throw exceptions.
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 OBJ04-J. Provide mutable classes with copy functionality to safely allow passing instances to untrusted code for more information).
Noncompliant Code Example
This noncompliant code example defines class SensitiveClass
, which contains a character array used to hold a file name, along with a Boolean
shared variable, initialized to false. This data is not meant to be copied; consequently, SensitiveClass
lacks a copy constructor.
Code Block | ||
---|---|---|
| ||
class SensitiveClass {
private char[] filename;
private Boolean shared = false;
SensitiveClass(String filename | ||
Code Block | ||
class MyPrivacy { //define class member fields //... public MyPrivacy(String passwd) { String actualPass; FileReader frthis.filename = new FileReader("Passfile.txt"filename.toCharArray(); } final void replace() { BufferedReader br = newif BufferedReader(fr!shared); { for(int actualPassi = br.readLine()0; i < filename.length; if(actualPass.equals(passwd))i++) { filename[i]= 'x' ;} } // return normally} final String }get() { elseif (!shared) { shared // exit the program, print an authentication error = true; return String.valueOf(filename); } else { //throw preventing the class object from being created new IllegalStateException("Failed to get instance"); } } publicfinal void useprintFilename() { //System.out.println(String.valueOf(filename)); } //... } |
The attacker can create a new instance of MyPrivacy class by using a cloneable subclass and by-pass the constructor.
Bypassing the constructor leads to bypassing the password check done in the constructor.
When a client requests a String
instance by invoking the get()
method, the shared
flag is set. To maintain the array's consistency with the returned String
object, operations that can modify the array are subsequently prohibited. As a result, the replace()
method designed to replace all elements of the array with an x
cannot execute normally when the flag is set. Java's cloning feature provides a way to circumvent this constraint even though SensitiveClass
does not implement the Cloneable
interface.
This class can be exploited by a malicious class, shown in the following noncompliant code example, that subclasses the nonfinal SensitiveClass
and provides a public clone()
method:
Code Block | ||
---|---|---|
| ||
class MaliciousSubclass extends SensitiveClass implements Cloneable {
protected MaliciousSubclass(String filename) {
super(filename);
}
@Override public MaliciousSubclass clone() { // Well-behaved clone() method
MaliciousSubclass s = null;
try {
s = (MaliciousSubclass)super.clone();
} | ||
Code Block | ||
class Test extends MyPrivacy implements Cloneable{ public static void somefunction(MyPrivacy obj) { try { Test t = (Test)obj.clone() }catch(Exception e) { System.out.println("not cloneable"); } if (t != null) t.use(); // Another object instantiated without knowing the password..... } } |
Compliant Solution 1
Classes should be made non cloneable to prevent this from occuring. The following method maybe implemented for achieving this.
Code Block |
---|
class MyPrivacy { //define class member fields //... public MyPrivacy(String passwdreturn s; } public static void main(String[] args) { String actualPass; FileReader frMaliciousSubclass ms1 = new FileReaderMaliciousSubclass("Passfilefile.txt"); BufferedReader brMaliciousSubclass ms2 = new BufferedReader(frms1.clone(); // Creates a copy String actualPasss = brms1.readLineget(); // Returns filename if(actualPass.equals(passwd)){ System.out.println(s); // Filename is "file.txt" ms2.replace(); // return normally // Replaces all characters with }'x' // Both ms1.get() else{ and ms2.get() will subsequently return filename = 'xxxxxxxx' ms1.printFilename(); // exitFilename the program, print an authentication error // preventing the class object from being created } } public void use(){ // } //... public final void clone() throws java.lang.CloneNotSupportedException{ throw new java.lang.CloneNotSupportedException(); } } |
Compliant Solution 2
One can also make a class non subclassable. This can be achieved by finalizing a class.
Code Block |
---|
 final class MyPrivacy {
// Rest of the definition remains the same
}
|
If, it is absolutely required to make the class cloneable, even then protective measures can be taken.
#1. If clone method is being over-riden, make it final
#2. If the class is reliant on a non-final clone method of one of the superclasses, then define the following
Code Block |
---|
public final void clone() throws java.lang.CloneNotSupportedException {
super.clone();
}
|
Risk Assessment
becomes 'xxxxxxxx'
ms2.printFilename(); // Filename becomes 'xxxxxxxx'
}
}
|
The malicious class creates an instance ms1
and produces a second instance ms2
by cloning the first. It then obtains a new filename
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 approach 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
to be final.
Code Block | ||
---|---|---|
| ||
final class SensitiveClass {
// ...
}
|
Compliant Solution (Final clone()
)
Sensitive classes should neither implement the Cloneable
interface nor provide a copy constructor. Sensitive classes that extend from a superclass that implements Cloneable
(and are cloneable as a result) must 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 made cloneable by defining a final
clone()
method that always fails.
Code Block | ||
---|---|---|
| ||
class SensitiveClass {
// ...
public final SensitiveClass clone()
throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
|
This class fails to prevent malicious subclasses but does protect the data in SensitiveClass
. Its methods are protected by being declared final. For more information on handling malicious subclasses, see OBJ04-J. Provide mutable classes with copy functionality to safely allow passing instances to untrusted code.
Risk Assessment
Failure to make sensitive classes noncopyable can permit violations of 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).
Recommendation
Rule |
---|
Severity | Likelihood | Remediation Cost | Priority | Level |
---|
OBJ07-J | Medium |
Probable |
Medium |
P8 | L2 |
References
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
CodeSonar |
| JAVA.CLASS.CLONE.CNC | clone Non-cloneable (Java) | ||||||
Parasoft Jtest |
| CERT.OBJ07.MCNC | Make your classes noncloneable |
Related Guidelines
CWE-498, Cloneable Class Containing Sensitive Information |
Bibliography
"Twelve Rules for Developing More Secure Java Code" | |
Section 10.6, "Java" |
...
http://www.javaworld.com/javaworld/jw-12-1998/jw-12-securityrules.html?page=4 http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/java.html