Lately, there has been a number of security vulnerabilities reported in Java. The latest one is reported just after a few days of JavaSE 7u11, which by itself a response to another vulnerability. It’s so bad to the point that people are being asked to uninstall Java (yes, just in the browser, but let’s face it, it’s way easier to just uninstall it entirely than to disable the Java plugin from all the browsers.)
I think this issue needs to be addressed at a deeper level pretty quickly, or else what’s still left of the client-side Java would be dead soon (if you think it’s already dead, then there’s nothing else to see in this post, so please move on.)
In fact, one could even argue that the entire Java platform is at risk — people (especially our users and those who are studying programming) do not understand that these issues are the sandbox breaches and therefore do not affect the server-side Java, nor embedded Java.
I think the main lesson should be that the sandbox model of Java is unmaintainable. It’s not just a few isolated bugs here and there, but it’s a structural problem.
For those of you who aren’t very familiar with Java, basically Java sandbox model is that:
- At runtime the entirety of Java core libraries are present (the exact same code you run on the server-side, including such abilities as forking processes, making network connections to anywhere, and accessing files)
- Code gets associated with the “code source” information to indicate if it’s trusted or not
- Library code (like one that accesses files) checks if the caller is trusted or not, and if not certain operations aren’t allowed.
The check in step #3 is implemented in a Java code (called SecurityManager), and that’s where the problem is. All the recent vulnerabilities in Java basically involves runtime reflection to replace the effective SecurityManager instance. This forces the reflection library to be inside the protection wall built by the security layer, which in turns forces many libraries in JavaSE to be inside the wall (such as JMX, which is used for the recent exploit, as well as XML stuff, which I was personally involved in.)
At this point, the protection wall is so long and windy that it’s impossible to defend. And I think it’s really all because we decided to protect reflection.
IMHO, a much simpler way to let untrusted code run is just to enforce checks on the native side, and simply stop trusting anything that runs as Java byte code. After all, we really need to just check stuff that interacts with the outside world, and every one of those has to be done by calling into native code. There’s very few of these calls. In this way, neither JMX nor XML APIs can be exploited, because they simply become just another untrusted code (that just so happen to be available all the time.) I’m no Flash expert, but IIUC, this is how Flash security model works.
In other words, create a new edition of Java, by adding one more to the ME/SE/EE mix. It is a new runtime environment that just shares the same virtual machine and the subset of core libraries. I think this is already consistent with the way “JavaFX” is marketed. While technically speaking it’s just a fancy UI library, it’s really marketed as an RIA platform along ME/SE/EE.
Imagine being able to define a large application into modules, with interfaces to define boundaries, mature module systems, efficient delivery and caching mechanisms. Debugger support, multi-threading, runs outside the browser for unit testing, programming in Ruby or Groovy â€¦ you get the idea. Think of it as GWT except translation, if you may.
As an avid Java fan, here’s my plea to Oracle — I want this for my Christmas present this year.
3 Comments Add yours
The Silverlight security model is another that is worth emulating. The run time is stripped back to only allow browser-style sandboxes – I.e.no access to local file system, no cross domain access, etc.
Client side file access is permitted if user picked a file from a File Dialog, or drag and dropped a file. There is also access to local storage a la HTML5, with quotas etc.
In addition it wouldn’t hurt if applets were ran inside a sepaprate restricted account, outside of the browser process.
The problem with your proposal is that it would make it impossible to run one JVM with several sandboxes, or with a sandbox plus a trusted component, etc. You would be enforcing process-level isolation, which works pretty well for security but is far less efficient because little of use can be shared. Maybe that is the price that has to be paid, but it means dropping many interesting use cases.
Another perspective is that one of Javaâ€™s original sins is in making the reflection classes, methods, and primitivesâ€”not just java.lang.reflect.*, but also Class (except when used as a type token!) & Object.getClass(), checkcast/instanceof, serialization, arguably even System.identityHashCode, and moreâ€”part of the â€œcoreâ€ language. All of these APIs, which violate referential transparency and the intuitive object model, really belong in a separate module accessible only to trusted code.
Good idea, but consider Java EE. If you have a public web hosting using Tomcat or JBoss AS, for instance, you use the SecurityManager to protect the server runtime from each application. It would mean that if the Java EE server wanted to check any priviledges it would have to either contain native code that would do it or have the SecurityManager re-implemented on it’s own. Or to have 1:1 mapping between server and application. Maybe it’s a general way Java EE should move to, because the isolation is quite complicated and not fully stable (such as 1 application steal all the memory, file descriptors, database sockets etc.). What do you think?