Developers often separate program logic across multiple classes or files to modularize code and to increase reusability. When developers modify a superclass (during maintenance, for example), the developer must ensure that changes in superclasses preserve all the program invariants on which the subclasses depend. Failure to maintain all relevant invariants can cause security vulnerabilities.
Noncompliant Code Example
In this code example, a class
Account stores banking-related information without any inherent security. Security is delegated to the subclass
BankAccount. The client application is required to use
BankAccount because it contains the security mechanism.
At a later date, the maintainer of the
Account class added a new method called
overdraft(). However, the
BankAccount class maintainer was unaware of the change. Consequently, the client application became vulnerable to malicious invocations. For example, the
overdraft() method could be invoked directly on a
BankAccount object, avoiding the security checks that should have been present. The following noncompliant code example shows this vulnerability:
Although this code works as expected, it adds a dangerous attack vector. Because the
overdraft() method has no security check, a malicious client can invoke it without authentication:
In this compliant solution, the
BankAccount class provides an overriding version of the
overdraft() method that immediately fails, preventing misuse of the overdraft feature. All other aspects of the compliant solution remain unchanged.
Alternatively, when the intended design permits the new method in the parent class to be invoked directly from a subclass without overriding, install a security manager check directly in the new method.
Noncompliant Code Example (
This noncompliant code example overrides the methods
compareTo() of the class
Calendar.after() method returns a
boolean value that indicates whether or not the
Calendar represents a time after that represented by the specified
Object parameter. The programmer wishes to extend this functionality so that the
after() method returns
true even when the two objects represent the same date. The programmer also overrides the method
compareTo() to provide a "comparisons by day" option to clients (for example, comparing today's date with the first day of the week, which differs among countries, to check whether it is a weekday).
java.util.Calendar class provides a
compareTo() method and an
after() method. The
after() method is documented in the Java API Reference [API 2014] as follows:
after()method returns whether this
Calendarrepresents a time after the time represented by the specified
Object. This method is equivalent to
compareTo(when) > 0
if and only if
Calendarinstance. Otherwise, the method returns
The documentation fails to state whether
compareTo() or whether
after(). In the Oracle JDK 1.6 implementation, the source code for
after() is as follows:
In this case, the two objects are initially compared using the overriding
CalendarSubclass.after() method, which invokes the superclass's
Calendar.after() method to perform the remainder of the comparison. But the
Calendar.after() method internally calls the
compareTo() method, which delegates to
CalendarSubclass.after() actually calls
CalendarSubclass.compareTo() and returns
The developer of the subclass was unaware of the implementation details of
Calendar.after() and incorrectly assumed that the superclass's
after() method would invoke only the superclass's methods without invoking overriding methods from the subclass. MET05-J. Ensure that constructors do not call overridable methods describes similar programming errors.
Such errors generally occur because the developer made assumptions about the implementation-specific details of the superclass. Even when these assumptions are initially correct, implementation details of the superclass may change without warning.
Compliant Solution (
This compliant solution uses a design pattern called Composition and Forwarding (sometimes also called Delegation) [Lieberman 1986], [Gamma 1995]. The compliant solution introduces a new forwarder class that contains a private member field of the
Calendar type; this is composition rather than inheritance. In this example, the field refers to
CalendarImplementation, a concrete instantiable implementation of the
Calendar class. The compliant solution also introduces a wrapper class called
CompositeCalendar that provides the same overridden methods found in the
CalendarSubclass from the preceding noncompliant code example.
Note that each method of the class
ForwardingCalendar redirects to methods of the contained
CalendarImplementation class, from which it receives return values; this is the forwarding mechanism. The
ForwardingCalendar class is largely independent of the implementation of the class
CalendarImplementation. Consequently, future changes to
CalendarImplementation are unlikely to break
ForwardingCalendar and are also unlikely to break
CompositeCalendar. Invocations of the overriding
after() method of
CompositeCalendar perform the necessary comparison by using the
CalendarImplementation.compareTo() method as required. Using
super.after(when) forwards to
ForwardingCalendar, which invokes the
CalendarImplementation.after() method as required. As a result,
java.util.Calendar.after() invokes the
CalendarImplementation.compareTo() method as required, resulting in the program correctly printing
Modifying a superclass without considering the effect on subclasses can introduce vulnerabilities. Subclasses that are developed with an incorrect understanding of the superclass implementation can be subject to erratic behavior, resulting in inconsistent data state and mismanaged control flow. Also, if the superclass implementation changes then the subclass may need to be redesigned to take into account these changes.
Sound automated detection is not currently feasible.
The introduction of the
entrySet() method in the
java.util.Hashtable superclass in JDK 1.2 left the
java.security.Provider subclass vulnerable to a security attack. The
Provider class extends
java.util.Properties, which in turn extends
Provider class maps a cryptographic algorithm name (for example,
RSA) to a class that provides its implementation.
Provider class inherits the
remove() methods from
Hashtable and adds security manager checks to each. These checks ensure that malicious code cannot add or remove the mappings. When
entrySet() was introduced, it became possible for untrusted code to remove the mappings from the
Provider failed to override this method to provide the necessary security manager check [SCG 2009]. This situation is commonly known as the fragile class hierarchy problem.
Guideline 4-6 / EXTEND-6: Understand how a superclass can affect subclass behavior
Item 16, "Favor Composition over Inheritance"
Design Patterns: Elements of Reusable Object-Oriented Software (p. 20)
"Using Prototypical Objects to Implement Shared Behavior in Object-Oriented Systems"