我正在实现一个沙盒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允许修改全局对象。用户可以毫无问题地执行以下代码块,并且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字节码。我也愿意接受其他建议来解决这个问题。
答案 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();