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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 Guideline 9-2: Beware of callback methods |
...