我正在实现一个沙盒JS环境,它允许用户上传他们的JS代码,并基于一组规则触发它。
我在Nashorn环境中禁用了Java访问,只允许访问一些实用类来执行一些操作,如HTTP请求、base64编码等。
目前,我为用户上传的每个JS代码创建ScriptEngine (Nashorn环境),但在我们的环境中,我们有许多预定义的JS代码,大多数用户都在使用它们。由于创建ScriptEngine的开销很大,我想对相同的JS代码块重用ScriptEngine。假设用户上传了以下代码:
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,并在调用main函数时更改绑定。然而,我找不到克隆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字节码。我也对解决这个问题的其他建议持开放态度。
发布于 2017-01-23 07:02:32
我相信ScriptContext对象会隔离每一次执行。
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("nashorn");
// Set up an isolated context.
Bindings bindings = engine.createBindings();
ScriptContext isolatedContext = new SimpleScriptContext();
isolatedContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
// Compile the function in the context.
engine.eval(code, isolatedContext);
ScriptObjectMirror fn = (ScriptObjectMirror) isolatedContext
.getAttribute("main");
// Call it whenever
fn.call("main", arg1, ar2, argEtc);https://stackoverflow.com/questions/40828426
复制相似问题