Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Masson 2011 added to Bibliography

...

This noncompliant code example, based on an example by Kabutz [Kabutz 2001], defines the constructor of the BankOperations class so that it performs SSN verification using the method performSSNVerification(). The implementation of the performSSNVerification() method assumes that an attacker does not know the correct SSN and trivially returns false.

Code Block
bgColor#FFcccc

public class BankOperations {
  public BankOperations() {
    if (!performSSNVerification()) {
      throw new SecurityException("Access Denied!");
    }
  }

  private boolean performSSNVerification() {
    return false; // Returns true if data entered is valid, else false. Assume that the attacker always enters an invalid SSN.
  }

  public void greet() {
    System.out.println("Welcome user! You may now use all the features.");
  }
}

public class Storage {
  private static BankOperations bop;

  public static void store(BankOperations bo) {
  // Only store if it is initialized
    if (bop == null) {
      if (bo == null) {
        System.out.println("Invalid object!");
        System.exit(1);
      }
      bop = bo;
    }
  }
}

public class UserApp {
  public static void main(String[] args) {
    BankOperations bo;
    try {
      bo = new BankOperations();
    } catch (SecurityException ex) { bo = null; }

    Storage.store(bo);
    System.out.println("Proceed with normal logic");
  }
}

...

When the constructor throws an exception, the garbage collector waits to grab the object reference. However, the object cannot be garbage-collected until after the finalizer completes its execution. The attacker's finalizer obtains and stores a reference by using the this keyword. Consequently, the attacker can maliciously invoke any instance method on the base class by using the stolen instance reference. This attack can even bypass a check by a security manager.

Code Block
bgColor#FFcccc

public class Interceptor extends BankOperations {
  private static Interceptor stealInstance = null;

  public static Interceptor get() {
    try {
      new Interceptor();
    } catch (Exception ex) {/* ignore exception */}
    try {
      synchronized (Interceptor.class) {
        while (stealInstance == null) {
          System.gc();
          Interceptor.class.wait(10);
        }
      }
    } catch (InterruptedException ex) { return null; }
    return stealInstance;
  }

  public void finalize() {
    synchronized (Interceptor.class) {
      stealInstance = this;
      Interceptor.class.notify();
    }
    System.out.println("Stole the instance in finalize of " + this);
  }
}

public class AttackerApp { // Invoke class and gain access
                           // to the restrictive features
  public static void main(String[] args) {
    Interceptor i = Interceptor.get(); // stolen instance

    // Can store the stolen object even though this should have printed
    // "Invalid Object!"
    Storage.store(i);

    // Now invoke any instance method of BankOperations class
    i.greet();

    UserApp.main(args); // Invoke the original UserApp
  }
}

...

This compliant solution declares the partially initialized class final so that it cannot be extended.

Code Block
bgColor#ccccff

public final class BankOperations {
  // ...
}

...

If the class itself can not be declared final, it can still thwart the finalizer attack by declaring its own finalize() method and making it final.

Code Block
bgColor#ccccff

public class BankOperations {
  public final void finalize() {
    // do nothing
  }
}

...

The compliant solution below demonstrates this design. Note that we have modified the performSSNVerification() method to throw an exception rather than returning false if the security check fails.

Code Block
bgColor#ccccff

public class BankOperations {
  public BankOperations() {
    this(performSSNVerification());
  }

  private BankOperations(boolean secure) {
    // secure is always true
    // constructor without any security checks
  }

  private static boolean performSSNVerification() {
    // Returns true if data entered is valid, else throws a SecurityException
    // Assume that the attacker just enters invalid SSN; so this method always throws the exception
    throw new SecurityException("Invalid SSN!");
  }

  // ...remainder of BankOperations class definition
}

...

Rather than throwing an exception, this compliant solution uses an initialized flag to indicate whether an object was successfully constructed. The flag is initialized to false and set to true when the constructor finishes successfully.

Code Block
bgColor#ccccff

class BankOperations {
  private volatile boolean initialized = false;

  public BankOperations() {
    if (!performSSNVerification()) {
      throw new SecurityException("Invalid SSN!");
    }

    this.initialized = true; // object construction successful
  }

  private boolean performSSNVerification() {
    return false;
  }

  public void greet() {
    if (!this.initialized) {
      throw new SecurityException("Invalid SSN!");
    }

    System.out.println(
        "Welcome user! You may now use all the features.");
  }
}

...

This noncompliant code example uses a nonfinal static variable. The Java Language Specification does not mandate complete initialization and safe publication even though a static initializer has been used. Note that in the event of an exception during initialization, the variable can be incorrectly initialized.

Code Block
bgColor#FFcccc

class Trade {
  private static Stock s;
  static {
    try {
      s = new Stock();
    } catch (IOException e) {
      /* does not initialize s to a safe state */
    }
  }
  // ...
}

...

This compliant solution guarantees safe publication by declaring the Stock field final.

Code Block
bgColor#ccccff

private static final Stock s;

...

[API 2006]

finalize()

[Darwin 2004]

§9.5, The Finalize Method

[Flanagan 2005]

§3.3, Destroying and Finalizing Objects

[JLS 2005]

§12.6, Finalization of Class Instances

 

§8.3.1, Field Modifiers

 

§17.5, Final Field Semantics

[Kabutz 2001]

Issue 032. Exceptional constructors - resurrecting the dead

[Lai 2008]

Java Insecurity: Accounting for Subtleties That Can Compromise Code

[Masson 2011]Secure your code against the finalizer vulnerability

 

OBJ10-J. Do not use public static nonfinal variables      04. Object Orientation (OBJ)      05. Methods (MET)