Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The class Trusted uses a package-private constructor in this noncompliant code example. It is desired that the code that exists outside the package be not allowed to create a new instance of an arbitrary class. However, since the API is public, it fails to achieve this condition. The bigger problem is that the attacker can exploit the method to create an instance of an arbitrary class as opposed to a trusted classIn this case, despite the package-private constructor, when an attacker passes Trusted.class as a parameter, the create() API returns an instance of the Trusted class.

Code Block
bgColor#FFcccc
package Safe;
public class Trusted {
  Trusted() { } // package private constructor
  public static <T> T create(Class<T> c) throws throws InstantiationException, ExceptionIllegalAccessException {
    return c.newInstance();
  }
}

package Attacker;
import Safe.Trusted;

public class Attack {
  public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    System.out.println(Trusted.create(Trusted.class)); // succeeds
  }
}

Compliant Solution

This compliant solution uses the java.beans.Beans API to explicitly specify the class loader that should be used to load the class obtained as the parameter. The attacker is unable to create an instance of the supplied class by using the current class loaderbecause the Beans.Instantiate() method has more stringent security checks that govern who is allowed reflective access and who is restricted.

Code Block
bgColor#ccccff
package Safe;
import java.beans.Beans;

class Trusted {
  Trusted() { }

  public static <T> T create(Class<T> c) {
    try {    
      SafeClassLoader scl = new SafeClassLoader();   
      ClassLoader cl = scl.getClass().getClassLoader();
      Object b = Beans.instantiate(cl, c.getName());
      return c.cast(b.getClass());
    } catch(Throwable t) { /* forward to handler */ }
      return null;
    }
}

// code outside the package
package Attacker;
import Safe.Trusted;

public class attack {
  public static void main(String[] args) {
  Trusted ac1 = new Trusted(); // unprivileged
  Trusted c = ac1.getClass();
  Trusted ac2 = (Trusted)Trusted.create(c System.out.println(Trusted.create(Trusted.class)); // loads with the specified classloader, unprivilegedthrows java.lang.IllegalAccessException
  }
}

Risk Assessment

Misuse of APIs that perform language access checks against the immediate caller only, can break data encapsulation.

...