...
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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.
...