Menu

Home Log in to Edit

Thorsten J. Krause

The Java-Sandbox

The java-sandbox allows to securely execute untrusted code, such as third-party or user generated code from within your application. It allows to specify resources and classes that may be used by the code, thus, separating the execution from the application's execution environment.

License

The java-sandbox is open source. The java-sandbox is available under the [LGPL 3.0].

Download

Sourcecode and binaries are available from Sourceforge. The only dependencies besides transloader are Apache's commons IO, commons lang (version 2.x) and commons collections (version 3.x) as well as Objenesis, which you can obtain from google code and javassist.

Version: 0.3
Released on 2013-06-19.
Download binary and sources from Sourceforge.Download reflective-sandcastle 0.1, hardened-reflective-sandcastle 0.1
Go to the [documentation], [API documentation], [sandcastle docuementation]

[Version:] 0.2
Released on 2013-06-12.
Download binary and sources from Sourceforge.
Go to the [documentation]
Version: 0.1
Released on 2013-05-31.
Download binary and sources from Sourceforge.
Go to the documentation

State of the Library

We see the library as experimental as we currently not have much experience with it. Thus, the API and functionality might change with future versions. To push this library into the right direction, we are happy for any feedback you might have.

Resources

Background and Motivation

Why Develop a Sandbox for Java

Why develop a sandbox for java, you may ask. Is there not already a library that does what you want? Regrettably, we found that this is not the case. There are several questions out there asking for something like a sandbox to execute untrusted code but the answer usually is: "this is not trivial, you might want to implement a custom SecurityManageror implement your own ClassLoaderand add ProtectionDomains and what not on the class to then use the builtin (and very inflexible) SecurityManager.

We had a very specific use-case in mind. We wanted to execute user generated code with different sets of permissions and furthermore these permission sets should be easily configurable during run-time of the application. For this we found java's builtin SecurityManager (which was introduced to secure applets in browsers) very bulky to work with and not flexible enough. On top, we wanted to specify permissions on a very fine grained level, that is on per class rather than per package. Thus, we developed the java-sandbox library.

Use cases

Our main motivation was that we wanted to secure ReportServer. ReportServer processes user generated code at several stages. For example, advanced filters can be specified using the unified expression language (specified inJSR-245; we use JUEL as implementation). Such expressions look harmless enough: for example, a user might use ${today.firstDay()} to specify the first day in the current month. However, behind the scenes JUEL evaluates this using lots of reflection and with a little experimenting its easy to access resources you shouldn't have:

${''.getClass().forName('java.lang.System').getMethod('exit', ''.getClass().forName('java.lang.Integer').getField('TYPE').get(null)).invoke(null, ''.hashCode())}

The above calls System.exit(). Something you wouldn't want. The java-sandbox allows us to use JUEL and only permit users to access whitelisted objects and functionality.

Groovy

Besides JUEL we wanted to use groovy. This is usually nothing an end user would get access to but at times it is nice to provide users with a simple text field to input some lines of code to, for example, manipulate strings instead of having a bulky GUI which in the end does not implement the functionality users would really like to use. Running groovy, of course, is a huge security problem, as users practically get access to the system having the same permissions as the application. One way out might be to plug into the compilation and syntax tree generation of groovy (or use a custom domain specific language instead of groovy). However, domain specific languages are time consuming to specify build and maintain and to fiddle with groovy's byte code generation may be error-prone. The java-sandbox allows to run groovy scripts in a restricted environment checking policy violations at run-time.

JasperReports

JasperReports Libraryis a reporting engine for generating print ready reports and is also available in ReportServer. A well known feature (bug?) of the JasperReports library is that of code injection (see, for eaxmple, here). Reports in jasper are defined using a custom XML dialect. From this file a java class (or groovy class, depending on the type of report) is generated to handle certain expressions. Thus, anybody who is allowed to manipulate reports can easily take over the entire system. Note that, to the best of our knowledge, this also applies to JasperSoft's very own business intelligence solution JasperReport Server.

Eclipse Birt
Eclipse Birt is a reporting engine quite similar to JasperReports library. Birt allows its users to enhance reports by scripts written in JavaScript (and internally executed using Rhino). Rhino makes it easy to access classes from the application scope and thus, again, any report designer can easily take over the entire system.

How the Java Sandbox works in just a few words

The java-sandbox basically consists of two components (an implementation of SecurityManagerand a custom ClassLoader)and a service class which allows to access the functionality. A sandbox can be started only using the security manager or using the classloader together with the security manager. We will briefly describe the difference between the two modes. For further information on how the java sandbox works internally have a look at the examples and explanations further down.
Assume service is an instance of the java-sandbox's service class. Then the easiest to create a sandbox is to call

String pw = service.restrict(context);
try{
    /* put untrusted code here */
} finally {
    service.releaseRestriction(pw);
}

With this setup only the security manager is enabled to supervise the execution of the untrusted code. The security manager is asked before certain system resources can be used or, for example, whether or not the System.exit() may be called (more information on the capabilities of security managers and the permission concept can be found here, and here). The context object of type SandboxContext allows to configure which permissions are given.
One problem with the above setup is that it is hardly possible to restrict access to classes and packages. Although security managers have a concept of being asked whether or not classes from certain packages may be loaded the security manager is asked exactly once by the classloader. Thus, if a package has been accessed outside the sandbox it is also cleared for use within the sandbox (at least in the eyes of the corresponding classloader).
To solve this problem we load the untrusted code with a custom classloader. The java-sandbox provides several easily accessible methods to do this. Usually you will setup a sandbox implementing the SandboxedEnvironment interface (which is similar to the Callable interface). The untrusted code then goes into the execute method.

SandboxedEnvironment<object> c = new SandboxedEnvironment<object>() {
   @Override
   public Object execute() {
      /* untrusted code */
      return null;
   }
};

service.runSandboxed(c.getClass(), context);


The runSandboxed methods accept a SandboxedEnvironment class object as well as a SandboxContext object as input. The environment is then loaded by a custom classloader while the context object describes the permissions available for sandboxed code. It then creates a sandbox and calls the environment's execute method. By loading the SandboxedEnvironment object in a custom classloader we have full control over which classes are loaded. The custom classloader also not only informs the security manager on packages but on classes that are to be loaded thus allowing to fine tune the sandbox to the specific needs.

Documentation

The documentation for the latest version can be found [here]. Documentation of the sandcastle extension can be found [here]. Go back to the [top of the page] for documentation for previous versions.

</object></object>

MongoDB Logo MongoDB