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

Geo*_*Geo 6 java security permissions scripting sandbox

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

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

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

这是另一个看起来不错的资源,但忽略了这一点:简单的JVM沙盒.它告诉粗心大意他们可以通过doPrivileged在包含具有极少权限的ProtectionDomain的自定义AccessControlContext中使用沙箱来编写沙箱,但当然这样做是没有意义的,因为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--; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这看起来很棘手且危险.在涉及安全性时尝试变得棘手是危险的,但鉴于这种情况,这真的是最好的解决方案吗?

Tom*_*ine 1

两个参数doPrivileged可用于减少权限。为该方法提供一个 acc,其中仅包含您想要授予的权限。

如果您使用减少的权限集启动脚本引擎,则权限检查将看到减少的权限集。喜欢 和AccessController.doPrivileged的人Method.invoke都会受到照顾。当然,这需要正确实现特定的脚本引擎实现。JDK 实现中的错误可以通过通常的方式报告。

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