How to Create a Java Sandbox

How do I create a Java sandbox?

You are looking for a security manager. You can restrict the permissions of an application by specifying a policy.

Create java sandbox based on security policies

As far as I know it's still SecurityManager that runs the security checks. But it seems to delegate to the AccessController nowadays.

First you'll need to switch on the security manager:

-Djava.security.manager

If you omit this argument there'll be no sandbox whatsoever.

Second you'll need to tell where to find the policy file:

-Djava.security.policy=

This will add your permissions to the ones already defined in your java home. The original sandbox rules in .../jre/lib/security/java.policy. However, if you want your policy to be the only one you'll need to use a double "=". This way you control completely what's allowed.

For example:

-Djava.security.policy==

I would advise you to use the "policytool" shipped with the Java. It's fairly basic but it helps you to write quickly a policy file with the correct syntax.

I hope this helps...

jvm sandbox for java application

That's what SecurityManager is for.

They even have a tutorial.

Sandbox against malicious code in a Java application

  1. Run the untrusted code in its own thread. This for example prevents problems with infinite loops and such, and makes the future steps easier. Have the main thread wait for the thread to finish, and if takes too long, kill it with Thread.stop. Thread.stop is deprecated, but since the untrusted code shouldn't have access to any resources, it would be safe to kill it.

  2. Set a SecurityManager on that Thread. Create a subclass of SecurityManager which overrides checkPermission(Permission perm) to simply throw a SecurityException for all permissions except a select few. There's a list of methods and the permissions they require here: Permissions in the JavaTM 6 SDK.

  3. Use a custom ClassLoader to load the untrusted code. Your class loader would get called for all classes which the untrusted code uses, so you can do things like disable access to individual JDK classes. The thing to do is have a white-list of allowed JDK classes.

  4. You might want to run the untrusted code in a separate JVM. While the previous steps would make the code safe, there's one annoying thing the isolated code can still do: allocate as much memory as it can, which causes the visible footprint of the main application to grow.

JSR 121: Application Isolation API Specification was designed to solve this, but unfortunately it doesn't have an implementation yet.

This is a pretty detailed topic, and I'm mostly writing this all off the top of my head.

But anyway, some imperfect, use-at-your-own-risk, probably buggy (pseudo) code:

ClassLoader

class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name is white-listed JDK class) return super.loadClass(name);
return findClass(name);
}
@Override
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the untrusted class data here
}
}

SecurityManager

class MySecurityManager extends SecurityManager {
private Object secret;
public MySecurityManager(Object pass) { secret = pass; }
private void disable(Object pass) {
if (pass == secret) secret = null;
}
// ... override checkXXX method(s) here.
// Always allow them to succeed when secret==null
}

Thread

class MyIsolatedThread extends Thread {
private Object pass = new Object();
private MyClassLoader loader = new MyClassLoader();
private MySecurityManager sm = new MySecurityManager(pass);
public void run() {
SecurityManager old = System.getSecurityManager();
System.setSecurityManager(sm);
runUntrustedCode();
sm.disable(pass);
System.setSecurityManager(old);
}
private void runUntrustedCode() {
try {
// run the custom class's main method for example:
loader.loadClass("customclassname")
.getMethod("main", String[].class)
.invoke(null, new Object[]{...});
} catch (Throwable t) {}
}
}

Sandbox Java code before compiling?

Java has some sandboxing mechanisms, but those have such a poor security track record that many recommend turning off Java in the browser entirely.

You could try sandboxing a VM inside it's own virtual OS with reduced privileges.

Alternatively, you could require the code to be run in a language like
Joe-E that is designed to allow Java programs to execute untrusted code.

Joe-E is a subset of Java that makes it easier to architect and implement programs with strong security properties that can be checked during a security review. It enables programmers to apply the principle of least privilege to their programs; implement application-specific reference monitors that cannot be bypassed; introduce and use domain-specific security abstractions; safely execute and interact with untrusted code; and build secure, extensible systems. Joe-E demonstrates how it is possible to achieve the strong security properties of an object-capability language while retaining the features and feel of a mainstream object-oriented language.

The degree to which Joe-E's designers had to depart from standard Java should give you an idea of how big a task it is to prevent untrusted Java code from abusing the ambient authority available from within a JVM.


While some of these approaches may protect you from abuse of authority (especially if layered together), none will prevent denial of service. If you're trying to run other people's code alongside your code, and it decides to try to take all the CPU and never give it back, your only option is often to kill the whole process.

Running an executable inside a sandbox from Java

AFAIK, no there isn't a way to do this. Certainly, not in pure / portable Java. (Java sandboxing is about managing what untrustworthy code can do, not how much resources it can use.)

In fact, I don't think there is even a reliable way to limit the CPU resources used by an external process.

The closest I can think of is trying to control thread (or process) priorities; see the Thread.setPriority(...) method.

How to sandbox a Java program

java -Djava.security.manager -java.security.policy=filename.policy HelloWorld.class

Where filename.policy is a file on the harddrive with no entries at all will "sufficiently" sandbox the code and prevent it from doing malicious writes/read on your PC.

The problem with just running that alone is that infinite loops are allowed and it would possibly consume all your CPU power and never stop.

The fix for that is indeed to create a new different program, which creates a new Process that it launches and only allows that Process to exist for a certain timeframe before terminating it (violently).

Here's some code I made for this (butchered from old code):

class TestProcess {
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();

public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
List<String> out = new ArrayList<>();
IntegerCallable ic = new TestProcess.IntegerCallable(out);
int returnVal = timedCall(ic);
}

private static <T> T timedCall(Callable<T> c) throws InterruptedException, ExecutionException, TimeoutException {
FutureTask<T> task = new FutureTask<>(c);
THREAD_POOL.execute(task);
return task.get(3, TimeUnit.SECONDS);
}

public static class IntegerCallable implements Callable<Integer> {
private final List<String> output;
private Process process;

public IntegerCallable(List<String> out) {
this.output = out;
}

public Integer call() throws Exception {
ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec");
pb.redirectErrorStream(true);
process = pb.start();

try (final Scanner scan = new Scanner(process.getInputStream())) {
while (scan.hasNext())
output.add(scan.nextLine());
}
return process.exitValue();
}
}
}

The line ProcessBuilder pb = new ProcessBuilder("java", "-cp", "execCommand/", "-Djava.security.manager", "-Djava.security.policy=execCommand/exec.policy", "-Xmx64M", "Exec"); needs to be edited to your needs. This line executes a Exec.class file inside a folder called execCommand, which is also the location of a exec.policy file, and give it a maximum of 64MB heap.



Related Topics



Leave a reply



Submit