是否应该使用自定义SecurityManager来沙箱javax.script.ScriptEngine?

时间:2013-11-14 09:14:34

标签: java security scripting permissions sandbox

javax.script JSR-223包的一个大问题是没有任何明显的方法来沙箱运行的脚本。所以显而易见的问题是:你如何沙箱JSR-223脚本?有人问过,甚至有几次尝试答案。

以下是关于这个问题的两个有趣的问题,但不幸的是忽略了这一点:

关键在于,这不仅仅是设置正确的安全策略或使用正确的ClassLoader,因为您尝试保护的代码不是Java代码,也没有类。您可以尝试通过使用ClassLoader为其提供一个特殊的ProtectionDomain来保护ScriptEngine,但只有在系统ClassLoader无法通过加载具有错误的ProtectionDomain的类来找到ScriptEngine来破坏您的工作时才会起作用。与作为JRE一部分的任何有用的ScriptEngine一起发生。

这是另一个看起来很好但却忽略了这一点的资源:Simple JVM sandboxing。它告诉粗心大意的是,他们可以在包含具有极少权限的ProtectionDomain的自定义AccessControlContext中使用doPrivileged对其脚本进行沙箱化,但当然这样做是没有意义的,因为doPrivileged仅对获取权限有用,并且对拒绝权限没有用。如果不受信任的代码已经存在于沙盒ProtectionDomain中,那么doPrivileged技巧根本不会执行任何操作,如果不受信任的代码位于非沙箱ProtectionDomain中,则它只能调用doPrivileged并完全绕过沙盒尝试。

真正的问题是如何解决这些问题?假设我们打算使用ProtectionDomains,似乎唯一的选择是给ScriptEngineManager一个自定义的ClassLoader,故意隐藏系统ClassLoader中的某些类。在这种情况下,我们如何决定将哪些类放入沙箱以及从系统ClassLoader获取哪些类?似乎没有任何可靠的方法来了解哪些类可能负责为脚本提供打破沙箱的方法,特别是对于尚不存在的ScriptEngines。

我能想到的唯一选择是我真正想问的问题。简单地忽略ProtectionDomains并实现具有用于评估脚本的沙箱模式的自定义SecurityManager是否是更好的解决方案?例如:

public final class SandboxMan extends SecurityManager {
    private int sandboxDepth = 0;
    @Override public void checkPermission(Permission permission) {
        if(sandboxDepth > 0) throw new SecurityException("Sandboxed: " + permission);
        else super.checkPermission(permission);
    }
    @Override public void checkPermission(Permission permission, Object context) {
        if(sandboxDepth > 0) throw new SecurityException("Sandboxed: " + permission);
        else super.checkPermission(permission, context);
    }
    public Object eval(ScriptEngine engine, String script) throws ScriptException {
        if(sandboxDepth == Integer.MAX_VALUE) throw new SecurityException("Sandbox depth");
        sandboxDepth++;
        try {
            return engine.eval(script);
        } finally { sandboxDepth--; }
    }
}

这看起来很棘手且危险。在涉及安全问题时尝试变得棘手是危险的,但考虑到这种情况,这真的是最好的解决方案吗?

1 个答案:

答案 0 :(得分:1)

双参数doPrivileged可用于减少特权。仅使用您想要提供的权限来提供方法。

如果您使用一组减少的权限启动脚本引擎,权限检查将看到缩减集。我会照顾AccessController.doPrivilegedMethod.invoke之类的内容。当然,这要求正确实现特定的脚本引擎实现。可以通过常规方式报告JDK实现中的错误。

您仍然需要运行不受信任的代码。即使是字节码,在Java中也可能很难防范。