Java's Object object cloning mechanism allows an attacker to manufacture new instances of a class, without executing its constructor. The new instances are made by copying the memory images of existing objects. Often this is not an acceptable way of creating new objects. By misusing the clone feature, an attacker can 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.
...
This noncompliant code example derives some functional behavior from the implementation of the class java.lang.StringBuffer
, prior to JDK v1.5. A class SensitiveClass
class is defined which contains a character array used to internally hold a filename, and a Boolean
shared variable, initialized to false
. When a client requests a String
instance by invoking the get()
method, the shared
flag is set. Operations that can modify the array are subsequently prohibited, to be consistent maintain the array's consistency with the returned String
object. Consequently, 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 illegally work around this constraint even though SensitiveClass
does not implement the Cloneable
interface.
Here, a A malicious class subclasses the non-final SensitiveClass
and provides a public
clone()
method. 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
. As 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 downplays any security efforts and severely violates the class's invariants.
Code Block | ||
---|---|---|
| ||
class SensitiveClass { private char[] filename; private Boolean shared = false; protected SensitiveClass(String filename) { this.filename = filename.toCharArray(); } protected void replace(){ if(!shared) for(int i=0;i<filename.length;i++) { filename[i]= 'x'; } } protected String get(){ if(!shared){ shared = true; return String.valueOf(filename); } else { throw new Error("Error getting instance"); } } protected void printFilename(){ System.out.println(String.valueOf(filename)); } } class MaliciousSubclass extends SensitiveClass implements Cloneable { protected MaliciousSubclass(String filename) { super(filename); } @Override public MaliciousSubclass Cloneclone() { // wellWell-behaved clone() method MaliciousSubclass s = null; try { s = (MaliciousSubclass)super.clone(); } catch(Exception e) { System.out.println("not cloneable"); } return s; } public static void main(String[] args){ MaliciousSubclass ms1 = new MaliciousSubclass("file.txt"); MaliciousSubclass ms2 = ms1.Cloneclone(); // createsCreates a copy String s = ms1.get(); // returnsReturns filename System.out.println(s); // filenameFilename is "file.txt" ms2.replace(); // replacesReplaces all characters with x' // bothBoth ms1.get() and ms2.get() will subsequently return filename = 'xxxxxxxx' ms1.printFilename(); // filenameFilename becomes 'xxxxxxxx' ms2.printFilename(); // filenameFilename becomes 'xxxxxxxx' } } |
Compliant Solution
...
It is also required to declare SensitiveClass
final
so as to avoid malicious subclassing. This stops an artful attacker from subclassing the sensitive class and creating several copies of the subclass, with the intention of introducing thread-safety issues.
...
An alternative is to declare the clone()
method final
so that it cannot be overridden. The implementation must still throw a CloneNotSupportedException
.
Risk Assessment
Failure to make sensitive classes noncloneable can severely violate the class invariants and provide malicious subclasses the opportunity to exploit the code to create new instances of objects, without even in the presence of the default security manager checks (by default(in the absence of custom security checks).
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC32- J | medium | probable | medium | P8 | L2 |
...