【发布时间】:2013-11-27 05:26:42
【问题描述】:
JSR-223 的 javax.script 包的一个大问题是缺乏任何明显的方法来沙箱运行的脚本。所以显而易见的问题是:您如何对 JSR-223 脚本进行沙箱处理?有人问过这个问题,甚至有人尝试过回答。
这里有两个关于这个问题的有趣问题,但遗憾的是没有抓住重点:
关键在于,这不仅仅是设置正确的安全策略或使用正确的 ClassLoader 的问题,因为您尝试保护的代码不是 Java 代码,它没有类。您可以尝试通过使用 ClassLoader 为 ScriptEngine 提供特殊的 ProtectionDomain 来保护 ScriptEngine,但这只有在系统 ClassLoader 无法找到 ScriptEngine 通过加载具有错误 ProtectionDomain 的类来挫败您的努力时才有效,这是绑定的任何被包含在 JRE 中的 ScriptEngine 都会发生这种情况。
这是另一个看起来不错但没有抓住重点的资源:@987654325@。它告诉粗心的人,他们可以通过在自定义 AccessControlContext 中使用 doPrivileged 对脚本进行沙箱化,该自定义 AccessControlContext 包含具有很少权限的 ProtectionDomain,但这样做当然没有意义,因为 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--; }
}
}
这看起来既棘手又危险。在涉及安全性时试图变得狡猾是很危险的,但考虑到这种情况,这真的是最好的解决方案吗?
【问题讨论】:
-
在我看来,OSGi 可能能够处理这种情况,但我不确定它是否适合您的应用程序的其余部分。
标签: java security scripting permissions sandbox