A rather dull worKLOG. This is just a scratchpad for solutions to IT problems that might be useful to someone else. Expect no opinions, no brilliant insights and definitely no pictures of pets or children. Expect stack traces, code snippets and other hints for the Google Indexer.

Tuesday, August 29, 2006

Java signed applet security insanity

I've been looking into using signed applets as a javascript-plastic bridge. The applets have to be signed so that they can make RMI connections to the Plastic Hub - this works well. Then through the wonders of LiveConnect you can call methods on the applet from JavaScript, and thanks to a magical object called JSObject you can make callbacks back to the JavaScript from the Java. This also, mostly, works well. However, try deploying the applet anywhere but localhost, and some of the JavaScript->Java calls fail with security exceptions (see below). Not all, just some. The reason? Apparently, if the JavaScript itself isn't signed, then any method calls originating in the JavaScript are treated as if the applet itself isn't signed - you lose all your signed applet privs. What kind of deranged madman thought that up? It's useless as a security benefit - all you do is put the controversial stuff into a separate thread, so that the JavaScript to Java calls merely set and get properties...so it's trivially subverted. Instead it just makes your code more complicated than it need be, and confounds the poor programmer with mysterious errors.

Implementation note: it's not good enough just to spawn an new thread in the method called by JavaScript, as this will inherit the security of the calling thread. Instead you need to instantiate a worker thread in (say) the start() method of the applet, and have the JavaScript-called method hand tasks to this worker. You can see a (rather naive) implementation here.

-----------
An alternative solution:
Put the "untrusted code" in:
  somemethod() {
...normal code here...
String user = (String) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return System.getProperty("user.name");
}
}
);




Stacktrace for google's benefit:
java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin.liveconnect.SecureInvocation$2.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin.liveconnect.SecureInvocation.CallMethod(Unknown Source)
at sun.plugin.liveconnect.SecureInvocation.access$300(Unknown Source)
at sun.plugin.liveconnect.SecureInvocation$CallMethodThread.run(Unknown Source)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.invoke.JSInvoke.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
at sun.plugin.liveconnect.PrivilegedCallMethodAction.run(Unknown Source)
... 6 more
Caused by: java.security.AccessControlException: access denied (java.net.SocketPermission 10.0.0.8:2234 connect,resolve)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkConnect(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.checkConnectPermission(Unknown Source)
at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at net.ladypleaser.rmilite.impl.RemoteInvocationHandlerImpl_Stub.invoke(Unknown Source)
at net.ladypleaser.rmilite.impl.LocalInvocationHandlerImpl.invokeRemote(LocalInvocationHandlerImpl.java:53)
at net.ladypleaser.rmilite.impl.LocalInvocationHandlerImpl.invoke(LocalInvocationHandlerImpl.java:41)
at $Proxy0.requestToSubset(Unknown Source)
at org.votech.plastic.managers.PlasticApplication.sendMessage(PlasticApplication.java:166)
at org.votech.plastic.managers.PlasticApplication.sendMessage(PlasticApplication.java:140)
at uk.ac.roe.PlasticHubApplet.sendLoadVOTable(Unknown Source)
... 16 more