Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: relatively minor edits

...

A fundamental principle of object-oriented design is that, when a subclass extends a superclass, the subclass's methods should must preserve the invariants provided by the superclass. Unfortunately, design principles fail to constrain attackers, who can (and do!) construct malicious classes that extend benign classes and provide methods that deliberately violate the invariants of the benign classes.

For instance, an immutable class that lacks the final qualifier can be extended by a malicious subclass that can change the state of the supposedly-immutable object. Further, the malicious subclass can impersonate the immutable object while actually remaining mutable. Such malicious subclasses can then violate program invariants on which clients depend, thus consequently introducing security vulnerabilities.

ThereforeAs a result, classes with invariants on which other code depends should be declared final, thereby preventing malicious subclasses from subverting their invariants. Furthermore, immutable classes must be declared final.

Some classes (hereafter known as superclasses) Superclasses must permit extension by trusted subclasses while simultaneously preventing extension by untrusted code. Consequently, declaring such superclasses to be final is infeasible, because it would prevent the required extension by trusted code. Such problems require careful design for inheritance.

Wiki Markup
Consider two classes belonging to different protection domains; one is malicious, and extends the other, which is trusted.  Consider an object of the malicious subclass with a fully qualified invocation of a method defined by the trusted superclass, and not overridden by the malicious class. In this case, the trusted superclass's permissions are examined to execute the method, with the consequence that the malicious object gets the method invoked inside the protection domain of the trusted superclass.  \[[Gong 2003|AA. Bibliography#Gong 03]\].

...

A method which receives an untrusted, non-final input argument must beware that other methods or threads might modify the input object. Some methods attempt to prevent modification by making a local copy of the input object. This is insufficient, because a shallow copy of an object may still allow it to point refer to mutable sub-objects, which may still be modified by other methods or threads. Some methods go farther and perform a deep copy of the input object. This mitigates the problem of modifiable sub-objects, but the method might still receive as an argument a mutable object that extends the input object class.

...

This malicious BigInteger class is clearly mutable, due to because of the setValue() method. Furthermore, the modPow() method is subject to precision loss (see NUM00-J. Detect or prevent integer overflow, NUM11-J. Check floating point inputs for exceptional values, NUM15-J. Ensure conversions of numeric types to narrower types do not result in lost or misinterpreted data and NUM17-J. Beware of precision loss when converting primitive integers to floating-point for more information). Any code that receives an object of this class, and assumes that the object is immutable will have unexpected behavior. (The This is particularly important because the BigInteger.modPow() method has several useful cryptographic applications.)

Noncompliant Code Example (Security Manager)

...

Unfortunately, throwing an exception from the constructor of a non-final class is insecure because it allows a finalizer attack (see guideline OBJ04-J. Do not allow access to partially initialized objects).

...

The guidelines FIO00-J. Defensively copy mutable inputs and mutable internal components and OBJ10-J. Provide mutable classes with copy functionality to allow passing instances to untrusted code safely discuss defensive copying in great depth.

Compliant Solution (Java SE 6

...

, public and private constructors)

This compliant solution invokes a security manager check as a side-effect of computing the boolean value passed to a private constructor (as seen in guideline OBJ04-J. Do not allow access to partially initialized objects). The rules for order of evaluation require that the security manager check must execute before invocation of the private constructor. Consequently, the security manager check also executes before invocation of any superclass's constructor. Note that the security manager check is made without regard to whether the object under construction has the type of the parent class or the type of a subclass (whether trusted or not).

Wiki Markup
This solution thwartsprevents the finalizer attack; it isappiles specific to Java SE 6 and onwardslater versions, where throwing an exception before the {{java.lang.Object}} constructor exits prevents execution of finalizers \[[SCG 2009|AA. Bibliography#SCG 09]\].

...