How can I securely execute some user supplied JS code using Java8 Nashorn?
The script extends some computations for some servlet based reports. The app has many diff
So far as I can tell, you can't sandbox Nashorn. An untrusted user can execute the "Additional Nashorn Built-In Functions" listed here:
https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/shell.html
which include "quit()". I tested it; it exits the JVM entirely.
(As an aside, in my setup the global objects, $ENV, $ARG, did not work, which is good.)
If I'm wrong about this, someone please leave a comment.
I've researched ways of allowing users to write a simple script in a sandbox that is allowed access to some basic objects provided by my application (in the same way Google Apps Script works). My conclusion was that this is easier/better documented with Rhino than with Nashorn. You can:
Define a class-shutter to avoid access to other classes: http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/
Limit the number of instructions to avoid endess-loops with observeInstructionCount: http://www-archive.mozilla.org/rhino/apidocs/org/mozilla/javascript/ContextFactory.html
However be warned that with untrusted users this is not enough, because they can still (by accident or on purpose) allocate a hugh amount of memory, causing your JVM to throw an OutOfMemoryError. I have not found a safe solution to this last point yet.
I asked this question on the Nashorn mailing list a while back:
Are there any recommendations for the best way to restrict the classes that Nashorn scripts can create to a whitelist? Or is the approach the same as any JSR223 engine (custom classloader on the ScriptEngineManager constructor)?
And got this answer from one of the Nashorn devs:
Hi,
Nashorn already filters classes - only public classes of non-sensitive packages (packages listed in package.access security property aka 'sensitive'). Package access check is done from a no-permissions context. i.e., whatever package that can be accessed from a no-permissions class are only allowed.
Nashorn filters Java reflective and jsr292 access - unless script has RuntimePermission("nashorn.JavaReflection"), the script wont be able to do reflection.
The above two require running with SecurityManager enabled. Under no security manager, the above filtering won't apply.
You could remove global Java.type function and Packages object (+ com,edu,java,javafx,javax,org,JavaImporter) in global scope and/or replace those with whatever filtering functions that you implement. Because, these are the only entry points to Java access from script, customizing these functions => filtering Java access from scripts.
There is an undocumented option (right now used only to run test262 tests) "--no-java" of nashorn shell that does the above for you. i.e., Nashorn won't initialize Java hooks in global scope.
JSR223 does not provide any standards based hook to pass a custom class loader. This may have to be addressed in a (possible) future update of jsr223.
Hope this helps,
-Sundar