5

I'm trying to add a scripting feature to our system where untrusted users can write simple scripts and have them execute on the server side. I'm trying to use Nashorn as the scripting engine.

Unfortunately, they added a few non-standard features to Nashorn:

https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/shell.html#sthref29

Scroll down to "Additional Nashorn Built-in Functions" and see the "quit()" function. Yup, if an untrusted user runs this code, the whole JVM shuts down.

This is strange, because Nashorn specifically anticipates running untrusted scripts. See: https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html#classfilter_introduction

Applications that embed Nashorn, in particular, server-side JavaScript frameworks, often have to run scripts from untrusted sources and therefore must limit access to Java APIs. These applications can implement the ClassFilter interface to restrict Java class access to a subset of Java classes.

Is there any way to prevent this behavior? How do I prevent users from running any of the additional functions?

ccleve
  • 15,239
  • 27
  • 91
  • 157
  • You should definitely start a new process to run your untrusted users' code. But also see... http://stackoverflow.com/questions/24466203/how-to-remove-java-apis-from-nashorn-engine – kervin Jun 30 '15 at 00:35
  • Thanks, that's a really useful link. But there are no options there to stop the quit(). I tried { "-strict", "--no-java", "--no-syntax-extensions", "--optimistic-types=true" } and quit() still quits. – ccleve Jun 30 '15 at 01:54

2 Answers2

8

Unfortunately, there is currently no way to control creation of non-standard global functions. One workaround is to simply delete these functions from the global object after the ScriptEngine has been initialized:

final NashornScriptEngineFactory engineManager = new NashornScriptEngineFactory();
final ScriptEngine engine = engineManager.getScriptEngine();
final Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.remove("print");
bindings.remove("load");
bindings.remove("loadWithNewGlobal");
bindings.remove("exit");
bindings.remove("quit");
System.err.println(engine.eval("'quit is ' + typeof quit"));

If you are using the Nashorn shell, a simple delete quit; will do.

If you are using the ScriptEngine interface and create multiple bindings, you'll have to do this with every global object/binding you create.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
3

If you're going to run "untrusted" scripts, please run your program with the SecurityManager turned on. With that "quit" would have resulted in SecurityException. ClassFilter by itself is not a replacement for SecurityManager. It is used to be used along with the SecurityManager. Please check the JEP on ClassFilter here: http://openjdk.java.net/jeps/202. The JEP clearly states this:

Make security managers redundant for scripts. Embedding applications should still turn on security management before evaluating scripts from untrusted sources. Class filtering alone will not provide a complete script "sandbox." Even if only untrusted scripts (with no additional Java classes) are executed, a security manager should still be utilized. Class filtering provides finer control beyond what a security manager provides. For example, a Nashorn-embedding application may prevent the spawning of threads from scripts or other resource-intensive operations that may be allowed by security manager.

kervin
  • 11,672
  • 5
  • 42
  • 59
A. Sundararajan
  • 4,277
  • 1
  • 15
  • 30