You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 70 Next »

The reflection APIs permit an object to access fields and methods of another object by name, rather than by reference. The JVM enforces policy compliance during such accesses by performing language access checks. 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 defined access checks. It is important to note, however, that these access checks consider only the language level visibility of the immediate caller. Consequently, unwary programmers can afford an opportunity for a privilege escalation attack by untrusted callers.

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

Because the java.lang.reflect.Field.setAccessible/getAccessible methods 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 guideline. 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 consequently are vulnerable.

Use of reflection complicates security analysis, and can introduce substantial security vulnerabilities. Consequently, programmers should avoid the use of the reflection APIs when it is feasible to do so. When use of reflection is necessary, exercise extreme caution.

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 accessing package-private fields without violating any language access checks because the immediate caller could have accessed the named field directly.

Allowing hostile code to pass arbitrary field names to the makeAccessible method can:

  • Leak information about field names, by throwing an exception for invalid or inaccessible field names. See guideline [EXC06-J. Do not allow exceptions to transmit sensitive information] for additional information. This example conforms with EXC06-J by catching the relevant exceptions at the end of the method.
  • Access potentially sensitive data that is visible to makeAccessible but is hidden from the attacking method. This privilege escalation attack can be difficult to find because the specific field(s) being accessed are controlled by strings in the attacker's code rather than by locally visible source code.
// 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);
      // Subsequent access to field f passes language access checks
      // because makeAccessible could have accessed the field via
      // ordinary field references
      System.out.println(f.getInt(c)); // prints 10
      f.setInt(c, 1);  // set to 1
      System.out.println(f.getInt(c)); // now prints 1
    }
    // log appropriately or throw sanitized exception; see EXC06-J
    catch(NoSuchFieldException nsfa){}
    catch(IllegalAccessException iae) {}
  }
}

class C {
  int i = 10; // package-private, data is sensitive
}

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. Declaring sensitive fields in other classes (e.g. Class c) to be private is also useful. Note, however, that when language access checks are overridden through use of java.lang.reflect.Field.setAccessible, the immediate caller gains access even to the private fields of other classes. Consequently, avoid granting the permission ReflectPermission with action suppressAccessChecks so that the security manager will block attempts to access private fields of other classes. See guideline [ENV04-J. Do not grant ReflectPermission with target suppressAccessChecks] for more information.

private final void makeAccessible() { // private final
  String fieldName = "i"; // hardcode
  C c = new C();
  // ...
} 

class C {
  private int i = 10; // private
}

Noncompliant Code Example

in this noncompliant code example, the programmer intends that code that exists outside the package should be prevented from creating a new instance of an arbitrary class. Consequently, the Trusted class uses a package-private constructor. However, because the API is public, an attacker can pass Trusted.class as a parameter to the create() method and so bypass the language access checks that prevent him from invoking the package-private constructor. The create() method returns an instance of the Trusted class.

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

In the presence of a security manager s, the Class.newInstance() method throws a security exception when either

  • an 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 class

The checkMemberAccess method "allows access to PUBLIC members, as well as access to classes that have the same class loader as the caller," which may be unsafe, as demonstrated in this noncompliant code example. sometimes it is inappropriate to rely on The class loader comparison in the second condition is often insufficient; for example all applets share the same class loader by convention, thus allowing a malicious applet to pass the security check in this case. Mitigate this vulnerability by invoking the checkPackageAccess() method directly.

Compliant Solution (Security Manager Check)

This compliant solution uses the getConstructors() method to check whether the class provided as an argument has public constructors. When public constructors are present, there is no relevant security issue because such constructors are already accessible even to malicious code. When public constructors are absent, the create() method uses the security manager's checkPackageAccess() method to ensure that all callers in the execution chain have sufficient permissions to access classes and their respective members defined in package Safe.

package Safe;
import java.beans.Beans;
import java.io.IOException;

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) {
        // throws an exception when access is forbidden          
        sm.checkPackageAccess("Safe");          
      }
    } 
    return c.newInstance(); // Safe to return     
  }  
}

The drawback of this compliant solution is that the class must be granted reflection permissions in order to permit the call to getConstructors().

Unknown macro: {mc}

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

public class Attack {
public static void main(String[] args)

Unknown macro: { Object o = Trusted.create(Trusted.class); }

}

Compliant Solution (java.beans Package)

This compliant solution uses the java.beans.Beans API to check whether the Class object being received has any public constructors.

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);      
  }  
}

The Beans.instantiate() method succeeds only 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. Unlike the previous compliant solution, this approach avoids the need for any reflection permissions.

Risk Assessment

Misuse of APIs that perform language access checks against the immediate caller only can break data encapsulation, leak sensitive information, or permit privilege escalation attacks.

Guideline

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 guideline on the CERT website.

Bibliography

[[Chan 1999]] java.lang.reflect AccessibleObject
[[SCG 2007]] Guideline 6-4 Be aware of standard APIs that perform Java language access checks against the immediate caller


[!The CERT Oracle Secure Coding Standard for Java^button_arrow_left.png!]      [!The CERT Oracle Secure Coding Standard for Java^button_arrow_up.png!]      [!The CERT Oracle Secure Coding Standard for Java^button_arrow_right.png!]

  • No labels