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

是否应该使用自定义SecurityManager来沙箱javax.script.ScriptEngine?,java,security,scripting,permissions,sandbox,Java,Security,Scripting,Permissions,Sandbox,的包的一个大问题是缺少任何明显的方法来沙箱运行的脚本。所以显而易见的问题是:如何对JSR-223脚本进行沙箱处理?有人问过这个问题,甚至有人试图回答 这里有两个关于这个问题的有趣问题,但不幸的是没有抓住要点: 关键是,这不仅仅是设置正确的安全策略或使用正确的类加载器的问题,因为您试图保护的代码不是Java代码,它没有类。您可以尝试通过使用类加载器为ScriptEngine提供一个特殊的ProtectionDomain来保护它,但这只能在系统类加载器找不到ScriptEngine的情况下起

的包的一个大问题是缺少任何明显的方法来沙箱运行的脚本。所以显而易见的问题是:如何对JSR-223脚本进行沙箱处理?有人问过这个问题,甚至有人试图回答

这里有两个关于这个问题的有趣问题,但不幸的是没有抓住要点:

关键是,这不仅仅是设置正确的安全策略或使用正确的类加载器的问题,因为您试图保护的代码不是Java代码,它没有类。您可以尝试通过使用类加载器为ScriptEngine提供一个特殊的ProtectionDomain来保护它,但这只能在系统类加载器找不到ScriptEngine的情况下起作用,以通过使用错误的ProtectionDomain加载该类来挫败您的努力,这在任何作为JRE一部分包含的脚本引擎中都是不可避免的

下面是另一个看起来不错但没有抓住要点的资源:。它告诉不小心的人,他们可以在自定义AccessControlContext中使用
doPrivileged
对脚本进行沙箱处理,该上下文包含权限非常少的ProtectionDomain,但这样做当然没有意义,因为
doPrivileged
只对获取权限有用,而对拒绝权限没有用处。如果不受信任的代码已经在沙盒保护域中,那么
doPrivileged
技巧将不会做任何事情,如果不受信任的代码在非沙盒保护域中,那么它可以调用
doPrivileged
并完全绕过沙盒尝试

真正的问题是如何解决这些问题?假设我们打算使用ProtectionDomains,那么唯一的选择似乎是为ScriptEngineManager提供一个定制的类加载器,该类加载器故意从系统类加载器中隐藏一些类。在这种情况下,我们如何决定将哪些类放入沙箱中,以及从系统类加载器中获取哪些类?似乎没有任何可靠的方法可以知道哪些类可能负责为脚本提供打破沙箱的方法,特别是对于还不存在的脚本引擎

我能想到的唯一选择是我真正想问的问题。简单地忽略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--; }
    }
}

这看起来既棘手又危险。当涉及到安全性时,试图变得狡猾是很危险的,但是考虑到这种情况,这真的是最好的解决方案吗?

两个参数
doPrivileged
可以用来减少特权。为该方法提供一个acc,该acc仅具有您想要授予的权限

如果启动脚本引擎时权限集减少,权限检查将看到减少的权限集。类似于
AccessController.doPrivileged
Method.invoke
的功能都得到了处理。当然,这需要正确实现特定脚本引擎实现。JDK实现中的bug可以用通常的方式报告


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

在我看来,OSGi可能能够处理这种情况,但我不确定它是否适合您的应用程序的其余部分。从什么意义上说,
AccessController.doPrivileged
被“处理”了?调用该方法不需要任何权限。