Imposing constraints or restrictions on method body, in Java

Have a look at java policy files. I've not used them, and I'm not sure they'll fit your problem exactly, but with some digging into the docs they may be a fit. Here's a couple SO questions that may be of help

Limiting file access in Java

What is a simple Java security policy for restricting file writes to a single directory?

And here's some documentation on the policy file.

http://docs.oracle.com/javase/6/docs/technotes/guides/security/PolicyFiles.html


You can restrict the classes used by untrusted code with a custom class loader:

public class SafeClassLoader extends ClassLoader {

    Set<String> safe = new HashSet<>();

    {
        String[] s = {
            "java.lang.Object",
            "java.lang.String",
            "java.lang.Integer"
        };
        safe.addAll(Arrays.asList(s));
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        if (safe.contains(name)) {
            return super.loadClass(name, resolve);
        } else {
            throw new ClassNotFoundException(name);
        }
    }
}

public class Sandboxer {
    public static void main(String[] args) throws Exception {
        File f = new File("bin/");
        URL[] urls = {f.toURI().toURL()};
        ClassLoader loader = new URLClassLoader(urls, new SafeClassLoader());
        Class<?> good = loader.loadClass("tools.sandbox.Good");
        System.out.println(good.newInstance().toString());
        Class<?> evil = loader.loadClass("tools.sandbox.Evil");
        System.out.println(evil.newInstance().toString());
    }
}

public class Good {
    @Override
    public String toString() {
        return "I am good";
    }
}

public class Evil {
    @Override
    public String toString() {
        new Thread().start();
        return "I am evil.";
    }
}

Running this will result in

I am good
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Thread
    at tools.sandbox.Evil.toString(Evil.java:7)
    at tools.sandbox.Sandboxer.main(Sandboxer.java:18)
Caused by: java.lang.ClassNotFoundException: java.lang.Thread
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 2 more

Of course, this assumes care is taken with the classes you white list. It also can't prevent denial of service stuff such as

while (true) {}

or

new long[1000000000];

I think that the direction in this question is good.

  • Use a specific ClassLoader lo load the class. Beware, that they're an interesting type of horse, it usually happens that the class itself is loaded by a parent classloader. Probably you want some sort of UrlClassLoader, and the parent classloader would be set to the Root classloader It is not enough, though.
  • Use threads to avoid infinite loops (rather implementing Runnable than extending Thread, like there) - this may be unnecessary if you're not worrying about it.
  • Use SecurityManager to avoid java.io operations

In addition to the above, I recommend 2 options:

Give the method a controller, that would contain the functions it can call

For example:

public void foo(Controller ctrl) {
}

public class Controller {
   public boolean commit();
   public boolean rollback();
}

This can give the user a handle, what operations are allowed.

Use an Intent-like command pattern

In Android, the components of the system are quite closed. They cannot directly communicate to each other, they only can fire an event, that "this happened", or "I want to do that".

This way the set of the usable commands are not restricted. Usually, if the methods do only small business logic, that is enough.