Reflection enables a Java program to analyze and modify itself. In particular, a program can discover the values of field variables and change them [Forman 052005], [Sun 022002]. The Java reflection API includes a method that enables fields that are normally inaccessible to be accessed under reflection. The following code prints out the names and values of all fields of an object someObject
of class SomeClass
:
...
When the default security manager is used, it prevents fields that are normally inaccessible from being accessed under reflection. The default security manager throws a java.security.AccessControlException
in these circumstances. However, java.lang.reflect.ReflectPermission
can be granted with action suppressAccessChecks
to override this default behavior.
For example, the Java Virtual Machine (JVM) normally protects private members of a class from being accessed by an object of a different class. When a method uses reflection to access class members (that is, uses the APIs belonging to the java.lang.reflect
package), the reflection uses the same restrictions. That is, a foreign object that cannot access private members of a class normally also cannot use reflection to access those members. However, a class with private members but also with a public method that uses reflection to indirectly access those members can inadvertently enable a foreign object to access those private members using the public method, bypassing the intended accessibility restrictions. Consequently, unwary programmers can create an opportunity for a privilege escalation attack by untrusted callers.
The following table lists the APIs that should be used with care [SCG 2009].
APIs that mirror language checksThat Mirror Language Checks |
---|
|
|
|
|
|
|
|
|
Because the setAccessible()
and getAccessible()
methods of class java.lang.reflect.Field
are used to instruct the JVM to override the language access checks, they perform standard (and more restrictive) security manager checks and consequently lack the vulnerability discussed in this rule. Nevertheless, these methods should be used only with extreme caution. The remaining set*()
and get*()
field reflection methods perform only the language access checks and are vulnerable.
...
In particular, reflection must not be used to provide access to classes, methods, and fields unless these those items are already accessible without the use of reflection. For example, the use of reflection to access or modify fields is not allowed unless those fields are already accessible and modifiable by other means, such as through getter and setter methods.
This rule is similar to rule MET04-J. Do not increase the accessibility of overridden or hidden methods, but it warns against using reflection, rather than inheritance, to subvert accessibility.
...
Allowing hostile code to pass arbitrary field names to the zeroField()
method can
- leak Leak information about field names by throwing an exception for invalid or inaccessible field names . See rule (see ERR01-J. Do not allow exceptions to expose sensitive information for additional information). This example complies with rule ERR01-J by catching the relevant exceptions at the end of the method.
- access Access potentially sensitive data that is visible to
zeroField()
but is hidden from the attacking method. This privilege escalation attack can be difficult to find during code review because the specific field (s) or fields being accessed are controlled by strings in the attacker's code rather than by locally visible source code.
Code Block | ||
---|---|---|
| ||
class FieldExample { private int i = 3; private int j = 4; public String toString() { return "FieldExample: i=" + i + ", j=" + j; } public void zeroI() { this.i = 0; } public void zeroField(String fieldName) { try { Field f = this.getClass().getDeclaredField(fieldName); // Subsequent access to field f passes language access checks // because zeroField() could have accessed the field via // ordinary field references f.setInt(this, 0); // logLog appropriately or throw sanitized exception; see EXC06-J } catch (NoSuchFieldException ex) { // reportReport to handler } catch (IllegalAccessException ex) { // reportReport to handler } } public static void main(String[] args) { FieldExample fe = new FieldExample(); System.out.println(fe.toString()); for (String arg : args) { fe.zeroField(arg); System.out.println(fe.toString()); } } } |
...
When you must use reflection, make sure that the immediate caller (method) is isolated from hostile code by declaring it private or final, as in this compliant solution.:
Code Block | ||
---|---|---|
| ||
class FieldExample { // ... private void zeroField(String fieldName) { // ... } } |
Note that when language access checks are overridden through use of using java.lang.reflect.Field.setAccessible
, the immediate caller gains access even to the private fields of other classes. Consequently, never grant the permission ReflectPermission
with action suppressAccessChecks
this ensures To ensure that the security manager will block attempts to access private fields of other classes, never grant the permission ReflectPermission
with action suppressAccessChecks
.
Compliant Solution (Nonreflection)
When a class must use reflection to provide access to fields, it must also provide the same access using a nonreflection interface. This compliant solution provides limited setter methods that grant all callers every caller the ability to zero out its fields without using reflection. If these setter methods comply with all other rules or security policies, the use of reflection also complies with this rule.
...
Code Block | ||
---|---|---|
| ||
package Safe; public class Trusted { Trusted() { } // package 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)); // succeedsSucceeds } } |
In the presence of a security manager s
, the Class.newInstance()
method throws a security exception when (a) s.checkMemberAccess(this, Member.PUBLIC)
denies creation of new instances of this class or (b) the caller's class loader is not the same class loader or an ancestor of the class loader for the current class, and invocation of s.checkPackageAccess()
denies access to the package of this class.
...
Code Block | ||
---|---|---|
| ||
package Safe; public class Trusted { Trusted() { } // package Package-private constructor static <T> T create(Class<T> c) throws InstantiationException, IllegalAccessException { return c.newInstance(); } } |
...
Code Block | ||
---|---|---|
| ||
import java.beans.Beans; import java.io.IOException; package Safe; public class Trusted { Trusted() { } public static <T> T create(Class<T> c) throws InstantiationException, IllegalAccessException { if (c.getConstructors().length == 0) { // No public constructors SecurityManager sm = System.getSecurityManager(); if (sm != null) { // throwsThrows an exception when access is not allowed sm.checkPackageAccess("Safe"); } } return c.newInstance(); // Safe to return } } |
...
This compliant solution uses the java.beans.Beans
API to check whether the Class
object being received has any public constructors.:
Code Block | ||
---|---|---|
| ||
public class Trusted { Trusted() { } public static <T> T create(Class<T> c) throws IOException, ClassNotFoundException { // Executes without exception only if there are public constructors ClassLoader cl = new SafeClassLoader(); Object b = Beans.instantiate(cl, c.getName()); return c.cast(b); } } |
...
Related Vulnerabilities
CERT Vulnerability #636312 #636312 describes an exploit in Java that allows malicious code to disable any security manager currently in effect. Among other vulnerabilities, the attack code exploited the following method defined in sun.awt.SunToolkit
, for Java 7:
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
SEC05-J | High | Probable | Medium | P12 | L1 |
Related Guidelines
Secure Coding Guidelines for the Java Programming LanguageSE, Version 35.0 | Guideline 6-5. 9-10 / ACCESS-10: Be aware of standard APIs that perform Java language access checks against the immediate caller |
...
Reflection can be used on Android, so the this rule is applicable. Also, the use of reflection may allow a developer to access private Android APIs and so requires caution.
...
|
...