Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: tweaked the wording a bit

A callback passes executable code as an argument to a method that is required to call back and execute that code Callbacks provide a means to register a method to be invoked or called back when an interesting event occurs. Callbacks are commonly used in object-oriented programming languages. Java uses callbacks for applet and servlet life cycle events of applets and servlets, AWT and Swing event notifications such as button clicks, and asynchronously reading and writing data from storage and even in Runnable.run() wherein a new thread automatically executes the specified run() method.

In Java, callbacks are widely typhically implemented using interfaces. The general structure of a callback is as follows.

...

Frequently, callback methods are given full privileges which can make them lucrative attractive targets. If these methods accept arguments from untrusted code, privilege escalation may occur.

...

Code Block
bgColor#FFcccc
public interface CallBack {
  void securityCritical(PrivilegedAction<String> action);
}

 
class CallBackImpl implements CallBack {
  public void securityCritical(PrivilegedAction<String> action) {
    AccessController.doPrivileged(action);        
  }
}
 
class Client {
  public void register(CallBack callback) {
    callback.securityCritical(new MaliciousUserLookupAction(7));
  }

  public static void main(String[] args) {
    Client client = new Client();
    CallBack callBack = new CallBackImpl();
    client.register(callBack);
  }
} 

...

Code Block
public class UserLookupAction implements PrivilegedAction<String> {
  private int userid;
 
  public UserLookupAction(int userid) {
    this.userid = userid;
  }
 
  public String run() {
    String name = null;
    try (InputStream fis = new FileInputStream("/etc/passwd")) {
      // Look up userid & assign to name
    } catch (IOException x) {
      name = null;
    }
    return name;
  }
}
 
class MaliciousUserLookupAction extends UserLookupAction {
  public MaliciousUserLookupAction(int userid) {
    super(userid);
  }


  public String run() {
    System.out.println("Executing untrusted code");
    return null;
  }
}

Consequently, the malicious code will execute with privileges of the class CallBackImpl that defines the callback in securityCritical() method.

Compliant Solution 

According to Oracle's secure coding guidelines [SCG 2010]:

...

This compliant solution amends the CallBack interface and instead of accepting the PrivilegedAction objects, the securityCritical() methods accepts methods accepts the user id to be searched for. The code contained within the UserLookupAction class is moved to the securityCritical() method.

Code Block
bgColor#ccccff
public interface CallBack {
  void securityCritical(int uid);
}

 
class CallBackImpl implements CallBack {
  public void securityCritical(int uid) {
    AccessController.doPrivileged(new PrivilegedAction<String>() {
      public String run() {
        String name;
        try (InputStream fis = new FileInputStream("/etc/passwd")) {
          // Look up userid & assign to name
        } catch (IOException x) {
          name = null;
        }
         return name;
      }
    });        
  }
}
 
class Client {
  public void register(CallBack callback) {
    callback.securityCritical(7);
  }

  public static void main(String[] args) {
    Client client = new Client();
    CallBack callBack = new CallBackImpl();
    client.register(callBack);
  }
} 

...

Bibliography

[API 2011]

Todo

[SCG 2010]

Guideline 9-3: Safely invoke java.security.AccessController.doPrivileged and

Guideline 9-2: Beware of callback methods

  

 

 

...