从java执行groovy脚本时如何阻止对某些类的访问?

时间:2014-09-24 12:59:25

标签: java groovy classloader sandbox

我对groovy很新,并且通常在java中编写脚本,而且我真的 希望我的问题有一个简单的解决方案。 在我们的应用程序中,用户可以执行他们编写的groovy脚本 他们自己,我们需要控制那些脚本可以做什么和不能做什么。 我读了很多关于沙盒groovy的东西,但我要么看 错误的地方或我忽略了显而易见的。 为简单起见,我有一个小例子来说明问题。 这是我的类加载器,它应该阻止java.lang.System 加载并可用于脚本:

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);
    }
}

这是一个试图调用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会抛出java.lang.SystemBeanInfo的例外情况 和java.lang.SystemCustomizer,但代码执行。 如果我使用javax.script类,也会发生同样的事情:

ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("Groovy");
Object o = engine.eval(code);
log.debug(o);

如果我尝试使用JavaScript引擎,它会按预期工作(只需替换 &#34; Groovy的&#34;使用&#34; JavaScript&#34;在上面的例子中。)

任何人都可以帮我吗?顺便说一下,我使用的是groovy-all-1.8.8.jar jdk1.7.0_55。

由于

3 个答案:

答案 0 :(得分:3)

我可以为此目的推荐Groovy Sandbox。与SecureASTCustomizer相反,它将检查在运行时是否允许动态执行。它拦截每个方法调用,对象分配,属性/属性访问,数组访问等等 - 因此您可以对允许的内容(白名单)进行非常精细的控制。

当然,允许的配置非常重要。例如,您可能希望允许使用String并使用substring之类的方法,但可能不使用execute上的String方法,这可能会被'rm -R ~/*'.execute()之类的方法利用。 1}}。 创建一个非常安全的配置是一项挑战,而且越多,您就越难以实现。

Groovy Sandbox的缺点是代码必须在注册的拦截器上运行,并且在执行期间会有性能损失。

此图像[1]显示了一个项目示例,其中我们使用Groovy Sandbox for Groovy代码输入。运行代码来修改脚本 - 所以如果那里的语句实际上是作为其中的一部分执行的,那么应用程序将在我可以执行屏幕截图之前退出;)

Example from a project where we used Groovy Sandbox

答案 1 :(得分:2)

也许您有兴趣将SecureASTCustomizerCompilerConfiguration结合使用。如果您担心安全问题,明确的白名单可能比黑名单更好。

def s = new SecureASTCustomizer()
s.importsWhiteList = [ 'a.legal.Klass', 'other.legal.Klass' ]

def c = new CompilerConfiguration()   
c.addCompilationCustomizers(s)

def sh = new GroovyShell(c)

看看那个类,它包含许多可以使用的选项。

答案 2 :(得分:0)

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.lang.Script;

public class SandboxGroovyClassLoader extends ClassLoader {

public SandboxGroovyClassLoader(ClassLoader parent) {
    super(parent);
}

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException    {
    if (name.startsWith("java.lang.System"))
        return null;
    return super.loadClass(name);
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    if (name.startsWith("java.lang.System"))
        return null;
    return super.loadClass(name, resolve);
}

static void runWithGroovyClassLoader() throws Exception {
    System.out.println("Begin runWithGroovyClassLoader");

    String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";

    GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
    Class<?> scriptClass = groovyClassLoader.parseClass(code);
    Object scriptInstance = scriptClass.newInstance();
    Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
    System.out.println(result);
    groovyClassLoader.close();
    System.out.println("End runWithGroovyClassLoader");
}

static void runWithSandboxGroovyClassLoader() throws Exception {
    System.out.println("Begin runWithSandboxGroovyClassLoader");
    ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
    SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);

    String code = "def hello_world() { java.lang.System.currentTimeMillis(); };";

    GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
    Class<?> scriptClass = groovyClassLoader.parseClass(code);
    Object scriptInstance = scriptClass.newInstance();
    Object result = scriptClass.getDeclaredMethod("hello_world", new Class[] {}).invoke(scriptInstance, new Object[] {});
    System.out.println(result);
    groovyClassLoader.close();
    System.out.println("End runWithSandboxGroovyClassLoader");
}

static void runWithSandboxGroovyShellClassLoader() throws Exception {
    System.out.println("Begin runWithSandboxGroovyShellClassLoader");

    String code = "java.lang.System.currentTimeMillis();";

    ClassLoader parentClassLoader = SandboxGroovyClassLoader.class.getClassLoader();
    SandboxGroovyClassLoader classLoader = new SandboxGroovyClassLoader(parentClassLoader);
    Thread.currentThread().setContextClassLoader(classLoader);

    GroovyShell shell = new GroovyShell();
    Script script = shell.parse(code);
    Object result = script.run();
    System.out.println(result);
    System.out.println("End runWithSandboxGroovyShellClassLoader");
}

public static void main(String[] args) throws Exception {

    runWithGroovyClassLoader();
    runWithSandboxGroovyClassLoader();
    runWithSandboxGroovyShellClassLoader();

}
}

这是你想要的吗?