I'm looking at a signed Applet that is heavily called from JavaScript. Obviously, the threads that originate from JavaScript are more heavily sandboxed than any thread started directly from within Java. For example, if a JavaScript thread calls into the Applet and logs something that causes the log file to roll, a security exception is thrown. Any thread started directly within the Applet will not experience this security exception. The solution here with log4j is to use the asynchronous appender.
But with other security exceptions (for example making use of Apache Axis in the signed Applet but in a JavaScript thread) there is no obvious way to have some asynchronous thread. Let's say I have the following code that if called from a Java thread will work and if called via JavaScript will fail with a SecurityException:
public void someMethodCalledFromJavaScript() {
// Stuff that would throw a SecurityException
}
I see three following options, but they may not all be valid. For the sake of this discussion, ignore whether or not the execution will be synchronous or asynchronous, as that's easily managed. I am having a difficult time understanding the details of the security model. Here are my three potential choices:
Start a new Thread (will this one even work?):
public void someMethodCalledFromJavaScript() {
new Thread(new Runnable() {
public void run() {
// Stuff that would throw a SecurityException
}
}).start();
}
Have the Applet have a thread ready to go at all times, triggered via the JavaScript-origin thread (highly simplified code here):
private volatile boolean doit = false;
// This code is running in a Thread, started @ Applet init time
public void alwaysWaiting() {
while (true) {
if (doit) {
doit = false;
// Stuff that would throw a SecurityException
}
}
}
public void someMethodCalledFromJavaScript() {
doit = true;
}
Use AccessController.doPrivileged:
public void someMethodCalledFromJavaScript() {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// Stuff that would throw a SecurityException
return null;
}
});
}
According to what I read of AccessController.doPrivileged
, you run with the intersection of the current security privs and the privs of the security domain of the code you're calling. This doesn't make sense to me, as if you're running with the intersection of a low and a high security domain, you'll just have the low security domain. So clearly I'm not understanding something.
The specific SecurityException
I'm seeing is this one:
java.security.AccessControlException: access denied (java.lang.RuntimePermission accessDeclaredMembers)
but of course I'm curious about the general case in the context of JavaScript calling into a signed Applet, and how I can allow a JavaScript-originated thread to run with the priv's of the signed Applet as if it were a thread that originated purely within the Applet.
Which choices above will even work, and which are better than others, and why.
Wont work because of reasons mentioned below
Will work of course, but that's more painful than calling doPrivileged
, yet has the same effect semantically.
Yes this will work.
Every access control check inspects the set of all stack frames on the stack of the current thread (including the stack frame leading up to the instantiation of the current thread, recursively). If there is a doPrivileged
frame, frames leading up to that frame are not included in the set (but the actual doPrivileged
frame is included).
If the privilege being checked is not in every single frame in that set, the check fails.
In other words, the current privileges of a thread are the intersection of privileges in this set.
So for example if privileged code doPrivileged
s some unprivileged code which tries to open a file, the check will fail. Likewise if unprivileged code doPrivileged
s privileged code that opens a file, the check will fail. But if unprivileged code invokes privileged code and the privileged code in turn calls doPrivileged
to open a file, the check will succeed.
In theory, you should be able to only grant your Java codebase the privileges it needs (perhaps access to some isolated directory), and then grant the same privileges to the JavaScript code that will use this privileged code, but I doubt any browser has such features. I'm surprised JavaScript even runs in another protection domain than Java.
I've never done JavaScript<->Java interop, but it seems no matter what you are going to have to make the methods that are invoked by JavaScript use doPrivileged
blocks on their entire body.
EDIT: As Sami said, be careful when invoking doPrivileged
blocks within the privileged code (and read his answer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With