安全地重复使用沙盒Nashorn容器

时间:2016-11-27 11:30:38

标签: javascript java containers bytecode nashorn

我正在实现一个沙盒JS环境,允许用户上传他们的JS代码并根据一组规则触发它。

我禁用了Nashorn环境中的Java访问,只允许访问一些实用程序类,用于一些操作,如HTTP请求,base64编码等。

目前,我为用户上传的每个JS代码创建ScriptEngine(Nashorn环境),但在我们的环境中,我们有许多预先定义的JS代码,我们的大多数用户都使用它们。由于创建ScriptEngine是昂贵的,我想重用ScriptEngine用于相同的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,并在调用main函数时更改绑定。但是我找不到克隆ScriptObjectMirror的方法。我的计划是在用户上传预编译的JS代码并在调用函数时使用它时创建新的范围。但是,Nashorn似乎不允许以编程方式创建引擎范围。

另一个问题是JS允许修改全局对象。用户可以毫无问题地执行以下代码块,并且Objectnull用于所有执行:

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字节码。我也愿意接受其他建议来解决这个问题。

1 个答案:

答案 0 :(得分:0)

我相信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); 个对象会隔离每次执行。

$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
} 

$sql = "SELECT * FROM pics WHERE id = '$id'";
$result = $conn->query($sql);
    // output data of each row
    while($row = $result->fetch_assoc()) {
       $dir = $row["dir"];
       $likes = $row["likes"];
    }

$sqlq = "UPDATE pics SET likes='$likes+1' WHERE id='$id'";

$conn->query($sqlq);

$conn->close();