Home > potd > POTD: Groovy Sandbox

POTD: Groovy Sandbox

April 29th, 2012

I posted the other day about Groovy’s SecureASTCustomizer and how it is harmful. In the end of that post, I suggested that doing the check dynamically would work better.

So in this installaition of “Project Of The Day”, I went ahead and implemented it. The result is Groovy sandbox.

My main idea is to confine the sandboxed script into its local object graph. The script should be allowed to mutate this graph all it wants, but it’ll be only allowed to include objects of known whitelisted “safe” types (such as String, List, Date etc.), and a few known safe instances, which acts as a bridge between the sandbox and the rest of the world. These bridge objects would have to be written carefully.

To use this, you have to add SandboxTransformer to your CompilerConfiguration first:

def cc = new CompilerConfiguration()
cc.addCompilationCustomizers(new SecureTransformer())
def binding = new Binding();
binding.robot = robot = new Robot();
def sh = new GroovyShell(binding,cc)

And now any script compiled via the resulting shell object will be sandboxed.

When a sandboxed script executes, all of the following operations are intercepted.

  • static/instance method invocation foo.bar(....)
  • object allocation new Foo(...)
  • property access and assignment zot=foo.bar / foo.bar=zot
  • attributes access and assignment zot=foo.@bar / foo.@bar=zot
  • array access and assignment zot=foo[bar] / foo[bar]=zot

To examine those calls and reject some of them, create your own implementation of GroovyInterceptor and registers it to the thread before you start executing the script:

def sandbox = new RobotSandbox()
sandbox.register()
try {
    sh.evaluate("robot.leftArm.move()")  // this is allowed to complete
    sh.evaluate("robot.selfDestruct()")  // no!
} finally {
    sandbox.unregister()
}

See the robot example for a complete example.

Now let’s see if I can get some feedback from real Groovy experts, and see if they’d be willing to take this into Groovy itself…

potd , ,

  1. Peter Gromov
    May 22nd, 2012 at 12:37 | #1

    Looks very promising! I’m considering using this inside IDEA. What do you think about it? Will you release this as a library?

  2. May 22nd, 2012 at 15:26 | #2

    Hey, it’s an honor to be helping IntelliJ IDEA, my favorite IDE! Yes, let me release what I have.

    One known TODO list is that it currently doesn’t intercept calls like “a||=b” or “a+=b” or “a%=b”. The way Groovy works make it tedious to intercept them all, so I haven’t done it.

    Any chance you guys can help me out here?

  3. Peter Gromov
    May 22nd, 2012 at 21:19 | #3

    Well, helping is quite possible, if you need it :)

    From what I see, such operators are just the usual method calls like ‘or’ or ‘mod’.

  4. June 9th, 2012 at 12:03 | #4

    @Peter Gromov
    Yes, it’s just that there are many of them.

    I’ve released 1.0 out of what I have.

  5. Peter Gromov
    June 11th, 2012 at 10:51 | #5

    @kohsuke
    Great, thanks! I’ve created an issue in our tracker to use it, which I invite you to watch: http://youtrack.jetbrains.com/issue/IDEA-87317

    I have a question though. I might be stupid, not knowing the basic things, but I can’t find an obvious way to obtain the jar (we don’t use Maven/Ivy/whatever in IDEA, just plain jars). Should I build it from source?

  6. March 22nd, 2013 at 02:34 | #6

    Hi Kohsuke,

    I am the writer of the SecureASTCustomizer stuff and I’ve just been pointed at this by a friend of mine, too bad I missed it. All you wrote about this is true and we should have made this more clear from the docs. Anyway, I wouldn’t consider this harmful as it’s the way it’s supposed to work. I must confess a very bad name for this class, but the idea behind it is to prevent some syntactic constructions at compile time, meaning “securing” the AST. For example, the calc stuff would not allow you to write explicit method calls.

    Note that now that we have static type checking, it would be possible to add a new transformation that goes beyond that, but it would still have flaws.

    Regarding your sandbox, there are still a lot of potential issues. First of them is @Grab and AST transformations that *must* be disallowed. Otherwise, it’s very easy to introduce global AST transforms or constructs like @CompileStatic that would bypass all of your checks. So I’d better use a combination of the two transforms. Even with that, I’m pretty certain there are ways to workaround checks. All we do is making it harder for an attacker to do so. In the end, you will always have to use a security manager: static and runtime checks are not enough.

    In the following weeks I’ll take some time to look closer at your code and see how we can improve it, that could indeed make a nice addition to Groovy core.

    Thanks!

  7. March 22nd, 2013 at 02:36 | #7

    Hi Kohsuke,

    I am the writer of the SecureASTCustomizer stuff and I’ve just been pointed at this by a friend of mine, too bad I missed it. All you wrote about this is true and we should have made this more clear from the docs. Anyway, I wouldn’t consider this harmful because it’s the way it’s supposed to work. I must confess a very bad name for this class, but the idea behind it is to prevent some syntactic constructions at compile time, meaning “securing” the AST. For example, the calc stuff would not allow you to write explicit method calls.

    Note that now that we have static type checking, it would be possible to add a new transformation that goes beyond that, but it would still have flaws.

    Regarding your sandbox, there are still a lot of potential issues. First of them is @Grab and AST transformations that *must* be disallowed. Otherwise, it’s very easy to introduce global AST transforms or constructs like @CompileStatic that would bypass all of your checks. So I’d better use a combination of the two transforms. Even with that, I’m pretty certain there are ways to workaround checks. All we do is making it harder for an attacker to do so. In the end, you will always have to use a security manager: static and runtime checks are not enough.

    In the following weeks I’ll take some time to look closer at your code and see how we can improve it, that could indeed make a nice addition to Groovy core.

    Thanks!

  1. No trackbacks yet.