Safely re-using sandboxed Nashorn containers

对着背影说爱祢 提交于 2019-12-12 03:04:25

问题


I'm implementing a sandboxed JS environment that allows users to upload their JS code and trigger it based on a set of rules.

I disabled Java access from Nashorn environment and only allow accessing some utility classes for a few operations such as HTTP requests, base64 encoding etc.

Currently, I create ScriptEngine (Nashorn environment) for each JS code uploaded by users but in our environment we have many pre-defined JS code which are used by most of our users. Since creating ScriptEngine is expensive, I want to re-use ScriptEngines for same JS code blocks. Let's say that the user uploaded the following code:

var main = function(event, userContext) {
   return event.get('time') + userContext.api_key;
}

userContext works similar to environment variables, the user sets context variables when uploading her code and we pass them to the main function. Since the JS code doesn't have any variable other than main, it's stateless so re-using the container is easy. However for the following code block, it's not trivial to re-use the container:

var test = [];
var main = function(event, userContext) {
   test.push(1);
   return event.get('time') + userContext.api_key;
}

I'm looking for a way to abstract the local variables for each user and re-use the environment with different local context so that Java will compile the JS code to Java bytecode and once and re-use the same bytecode and invoke it in a different context, just like the relation between classes and objects.

One way to do it is to create a ENGINE_SCOPE for each user and change bindings when invoking the main function. However I couldn't find a way to clone ScriptObjectMirror. My plan was to create new scope when a user uploads a pre-compiled JS code and use it when invoking the function. However Nashorn doesn't seem to allow creating engine scope programatically.

Another problem is that JS allows modifying global objects. The user can execute the following code block without any problem and Object will be null for all executions:

var test = [];
var main = function(event, userContext) {
   Object = null;
   return event.get('time') + userContext.api_key;
}

Therefore, I also need to disable modifying the variables in GLOBAL_SCOPE but I couldn't find a way to do it.

I'm aware that there might be other security problems for re-using containers and the safe way is to create different containers for each JS code uploaded by users. However creating Nashorn environment is quite expensive compared to V8 and if there are too many Nashorn environments in runtime, Java fills up the Code Cache since it tries to compile the JS code blocks to Java bytecode. I'm also open to other suggestions to solve this problem.


回答1:


I believe ScriptContext objects will isolate each execution.

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/safely-re-using-sandboxed-nashorn-containers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!