Wiki Markup |
---|
It is possible to reflectively access fields and methods of one object from another. Language access checks are enforced by the JVM to ensure policy compliance, while doing so. For instance, although an object is not normally allowed to access private members or invoke methods of another class, the APIs belonging to the {{java.lang.reflect}} package allow an object to do so contingent upon performing the language access checks. |
...
The table below lists the APIs that should be used with care. |
...
||APIs that mirror language |
...
checks|| |{{java.lang.Class.newInstance |
...
}}| |{{java.lang.reflect.Constructor.newInstance |
...
}}| |{{java.lang.reflect.Field.get* |
...
}}| |{{java.lang.reflect.Field.set* |
...
}}| |{{java.lang.reflect.Method.invoke |
...
}}| |{{java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater |
...
}}| |{{java.util.concurrent.atomic.AtomicLongFieldUpdater.newUpdater |
...
}}| |{{java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater |
...
}}| Note that the language access checks do not apply to {{java.lang.reflect.Field.setAccessible/getAccessible}} methods but to the remaining {{set*}} and {{get*}} field methods. The former APIs are protected by standard security manager checks. |
...
h2. Noncompliant Code Example |
...
In this noncompliant code snippet, the package-private field {{i}} of class {{C}} can be accessed from class {{ReflectionExample}}. Method {{makeAccessible}} accepts {{fieldName}} as an input parameter which can be supplied by untrusted code. This is dangerous because despite the untrusted code not having the same capabilities as that of the immediate caller (method {{makeAccessible}}), it is allowed to carry out sensitive operations. In this case, the immediate caller has the capability of modifying package-private fields without triggering any language access checks. Hostile code should not be allowed to make such modifications by using it as an oracle. |
...
{code | ||
:bgColor | =#FFcccc | } // Class 'ReflectionExample' and 'C' belong to the same package public class ReflectionExample { public static void makeAccessible(String fieldName) { C c = new C(); try { Field f = c.getClass().getDeclaredField(fieldName); System.out.println(f.getInt(c)); // prints 10 f.setInt(c, 1); // set to 1; bypasses language access checks System.out.println(f.getInt(c)); // now prints 1 } catch(NoSuchFieldException nsfa){} catch(IllegalAccessException iae) {} } } class C { int i = 10; // package-private } {code} h2. Compliant Solution |
...
Do not operate on tainted inputs provided by untrusted code. Likewise, do not return values to an untrusted caller. If you must use Reflection, make sure that the immediate caller (method) is isolated from hostile code by declaring it {{final}}, reducing it's scope to {{private}} and making it {{non-static}}. Also, declare sensitive fields in other classes (Class {{c}}) as {{private}}. |
...
{code | ||
:bgColor | =#ccccff | } private final void makeAccessible() { // private final String fieldName = "i"; // hardcode C c = new C(); // ... } class C { private int i = 10; // private } {code} The permission {{ReflectPermission}} with action {{suppressAccessChecks}} should also not be granted so that the security manager blocks attempts to access private fields of other classes. (See [ENV04-J. Do not grant ReflectPermission with target suppressAccessChecks |
...
Noncompliant Code Example
...
]) h2. Noncompliant Code Example 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. In 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 | ||
---|---|---|
| ||
{code:bgColor=#FFcccc} package Safe; public class Trusted { Trusted() { } // package private constructor public static <T> T create(Class<T> c) throws InstantiationException, IllegalAccessException { 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 } } {code} In the presence of a security manager {{s}}, the {{Class.newInstance()}} method throws a security exception when either: |
...
{quote} * invocation of {{s.checkMemberAccess(this, Member.PUBLIC)}} denies creation of new instances of this class |
...
* the caller's class loader is not the same as or an ancestor of the class loader for the current class and invocation of {{s.checkPackageAccess()}} denies access to the package of this |
...
For the first condition, "The default policy is to allow access to PUBLIC members, as well as access to classes that have the same class loader as the caller.". This may be unsafe, as demonstrated in this noncompliant code example. For the second condition, sometimes it is inappropriate to rely on the class loader comparison. The checkPackageAccess()
method should be independently called.
Compliant Solution
This compliant solution checks whether the Class object has any public
constructors. If it does, the java.beans.Beans
API is used to explicitly specify the class loader that should be used to instantiate the class object. If no public
constructors are present, the security manager's checkPackageAccess()
method is invoked to ensure that the caller has sufficient permissions to access members of the package Safe
.
Code Block | ||
---|---|---|
| ||
class {quote} For the first condition, "The default policy is to allow access to PUBLIC members, as well as access to classes that have the same class loader as the caller.". This may be unsafe, as demonstrated in this noncompliant code example. For the second condition, sometimes it is inappropriate to rely on the class loader comparison. The {{checkPackageAccess()}} method should be independently called. h2. Compliant Solution (security manager check) If no {{public}} constructors are present, the security manager's {{checkPackageAccess()}} method is invoked to ensure that all callers in the execution chain have sufficient permissions to access classes and their respective members defined in package {{Safe}}. {code:bgColor=#ccccff} package Safe; import java.beans.Beans; import java.io.IOException; public class Trusted { Trusted() { } public static <T> T create(Class<T> c) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { if(c.getConstructors().length == 0) { // No public constructors SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPackageAccess("Safe"); } } return c.newInstance(); // Safe to return } } {code} The drawback of this compliant solution is that the class must be granted reflection permissions so that the call to {{getConstructors()}} succeeds. {mc} // HIDDEN TEXT // code outside the package package Attacker; import Safe.Trusted; public class Attack { public static void main(String[] args) { Object o = Trusted.create(Trusted.class); } } {mc} h2. Compliant Solution ({{java.beans}} package) This compliant solution checks whether the Class object being received has any {{public}} constructors with the help of the {{java.beans.Beans}} API. {code:bgColor=#ccccff} public class Trusted { Trusted() { } public static <T> T create(Class<T> c) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException { // Executes without exception only if there are public constructors ClassLoader cl = new SafeClassLoader(); Object b = Beans.instantiate(cl, c.getName()); return c.cast(b); } } // code outside the package package Attacker; import Safe.Trusted; public class Attack { public static void main(String[] args) { Object o = Trusted.create(Trusted.class); } } |
Risk Assessment
Misuse of APIs that perform language access checks against the immediate caller only, can break data encapsulation.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC06- J | high | probable | medium | P12 | L1 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
{code} The {{Beans.instantiate()}} method only succeeds when the class being instantiated has a {{public}} constructor, otherwise it throws an {{IllegalAccessException}}. The method uses a class loader argument along with the name of the class to instantiate. This compliant solution does not require any additional reflection permissions as opposed to the previous one. h2. Risk Assessment Misuse of APIs that perform language access checks against the immediate caller only, can break data encapsulation. || Rule || Severity || Likelihood || Remediation Cost || Priority || Level || | SEC06- J | high | probable | medium | {color:red}{*}P12{*}{color} | {color:red}{*}L1{*}{color} | h3. Automated Detection TODO h3. Related Vulnerabilities Search for vulnerabilities resulting from the violation of this rule on the [CERT website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+SEC0-J]. h2. References \[[Chan 99|AA. Java References#Chan 99]\] java.lang.reflect AccessibleObject \[[SCG 07|AA. Java References#SCG 07]\] Guideline 6-4 Be aware of standard APIs that perform Java language access checks against the immediate caller |
...
---- [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_left.png!|SEC05-J. Do not expose standard APIs that use the immediate caller's class loader instance to untrusted |
...
code] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_up.png!|02. Platform Security (SEC)] [!The CERT Sun Microsystems Secure Coding Standard for Java^button_arrow_right.png!|SEC07-J. Declare classes that derive from a sensitive class or implement a sensitive interface final] |