【发布时间】:2016-11-27 11:30:38
【问题描述】:
我正在实现一个沙盒 JS 环境,允许用户上传他们的 JS 代码并根据一组规则触发它。
我禁用了 Nashorn 环境中的 Java 访问,只允许访问一些实用程序类以进行一些操作,例如 HTTP 请求、base64 编码等。
目前,我为用户上传的每个 JS 代码创建 ScriptEngine(Nashorn 环境),但在我们的环境中,我们有许多预定义的 JS 代码,大多数用户都在使用它们。由于创建ScriptEngine 的成本很高,我想将ScriptEngines 重新用于相同的JS 代码块。假设用户上传了以下代码:
var main = function(event, userContext) {
return event.get('time') + userContext.api_key;
}
userContext 的作用类似于环境变量,用户在上传代码时设置上下文变量,我们将它们传递给main 函数。由于 JS 代码除了 main 之外没有任何变量,它是无状态的,因此重用容器很容易。但是对于下面的代码块,重用容器并不是一件容易的事:
var test = [];
var main = function(event, userContext) {
test.push(1);
return event.get('time') + userContext.api_key;
}
我正在寻找一种方法来为每个用户抽象局部变量并重新使用具有不同本地上下文的环境,以便 Java 将 JS 代码编译为 Java 字节码,然后重新使用相同的字节码并调用它在不同的上下文中,就像类和对象之间的关系一样。
一种方法是为每个用户创建一个ENGINE_SCOPE,并在调用主函数时更改绑定。但是我找不到克隆ScriptObjectMirror 的方法。我的计划是在用户上传预编译的 JS 代码时创建新范围,并在调用函数时使用它。但是 Nashorn 似乎不允许以编程方式创建引擎范围。
另一个问题是 JS 允许修改全局对象。用户可以毫无问题地执行以下代码块,Object 将是 null 对于所有执行:
var test = [];
var main = function(event, userContext) {
Object = null;
return event.get('time') + userContext.api_key;
}
因此,我还需要禁用修改GLOBAL_SCOPE 中的变量,但我找不到方法。
我知道重复使用容器可能存在其他安全问题,安全的方法是为用户上传的每个 JS 代码创建不同的容器。然而,与 V8 相比,创建 Nashorn 环境非常昂贵,如果运行时 Nashorn 环境过多,Java 会填满 Code Cache,因为它会尝试将 JS 代码块编译为 Java 字节码。我也愿意接受其他解决此问题的建议。
【问题讨论】:
标签: javascript java containers bytecode nashorn