I'm pretty new to groovy, and scripting in java generally, and I really
hope there is a simple solution for my problem.
In our application, the users can execute groovy scripts which they write
themselves, and we need to control what those scripts can and can not do.
I read a lot of stuff about sandboxing groovy, but either I am looking at
wrong places or I am overlooking the obvious.
To make it simple, I have a small example which demonstrates the problem.
This is my class loader which should prevent java.lang.System
from being
loaded and available to scripts:
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("java.lang.System")) {
throw new ClassNotFoundException("Class not found: " + name);
}
return super.loadClass(name);
}
}
And this is a simple program that tries to call System.currentTimeMillis()
:
public static void main(String[] args) {
String code = "java.lang.System.currentTimeMillis();";
ClassLoader classLoader = new MyClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
GroovyShell shell = new GroovyShell();
Script script = shell.parse(code);
Object result = script.run();
log.debug(result);
}
MyClassLoader
throws exceptions for java.lang.SystemBeanInfo
and java.lang.SystemCustomizer
, but the code executes.
Same thing happens if I use javax.script
classes:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("Groovy");
Object o = engine.eval(code);
log.debug(o);
And if I try it with JavaScript engine, it works as expected (just replace "Groovy" with "JavaScript" in the above example).
Can anyone help me with this? BTW, I'm using groovy-all-1.8.8.jar, with jdk1.7.0_55.
Thanks
Groovy classes and scripts are usually stored in.groovy files Scripts contain Groovy statements without any class declaration. Scripts can also contain method definitions outside of class definitions. It can be compiled and fully integrated with traditional Java application.
The GroovyScriptEngine class is particularly for those applications which rely on the reloading of a script and its dependencies. Although we have these additional features, the implementation has only a few small differences:
Groovy source code gets compiled into Java Bytecode so it can run on any platform that has JRE is installed. Groovy also performs a lot of tasks behind the scene that makes it more agile and dynamic. Groovy language can be used as a scripting language for the Java platform.
Note: You can also install Groovy using the Zip file or as an Eclipse IDE. In this Groovy tutorial, we will stick to Windows Installer Step 3) Launch the downloaded installer. Select language and click OK Step 4) Launch. In welcome screen, click NEXT Step 5) Agree with the license terms Step 6) Select components you want to install and click NEXT
I can recommend Groovy Sandbox for this purpose. In contrast to SecureASTCustomizer
it will check if an execution is allowed dynamically at runtime. It intercepts every method call, object allocations, property/attribute access, array access, and so on - and you thus have a very fine grained control on what you allow (white-listing).
Naturally the configuration on what is allowed is very important. For example you may want to allow using String
s and use methods like substring
, but probably not the execute
method on String
, which could be exploited with something like 'rm -R ~/*'.execute()
.
Creating a configuration that is really safe is a challenge, and it is more difficult the more you allow.
Downside of the Groovy Sandbox is that the code must run with the interceptor registered and you will have a performance penalty during execution.
This image [1] shows an example from a project where we used Groovy Sandbox for Groovy code entered by the user. The code is run to valide the script - so if the statement there would actually be executed as part of it, the application would have exited before I could do the screenshot ;)
Perhaps you'd be interested in using a SecureASTCustomizer
in conjunction with a CompilerConfiguration
. If you are concerned with security, an explicit white list might be better than a black list.
def s = new SecureASTCustomizer()
s.importsWhiteList = [ 'a.legal.Klass', 'other.legal.Klass' ]
def c = new CompilerConfiguration()
c.addCompilationCustomizers(s)
def sh = new GroovyShell(c)
Take a look at that class, it contains a lot of options that are ready to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With