GithubHelp home page GithubHelp logo

delight-nashorn-sandbox's Introduction

Nashorn Sandbox

A secure sandbox for executing JavaScript in Java apps using the Nashorn engine.

Also see Graal JS Sandbox and Rhino Sandbox.

Part of the Java Delight Suite.

Maven Central

Note: Use version 0.3.x if you are using a Java version older than Java 20.

Open Security Issues: # 73 # 117

Usage

The sandbox by default blocks access to all Java classes.

Classes, which should be used in JavaScript, must be explicitly allowed.

NashornSandbox sandbox = NashornSandboxes.create();
     
sandbox.allow(File.class);
     
sandbox.eval("var File = Java.type('java.io.File'); File;")

Or you can inject your Java object as a JS global variable

NashornSandbox sandbox = NashornSandboxes.create();

sandbox.inject("fromJava", new Object());

sandbox.eval("fromJava.getClass();");

The sandbox also allows limiting the CPU time and memory usage of scripts. This allows terminating scripts which contain infinite loops and other problematic code.

NashornSandbox sandbox = NashornSandboxes.create();
     
sandbox.setMaxCPUTime(100);
sandbox.setMaxMemory(50*1024);
sandbox.allowNoBraces(false);
sandbox.setMaxPreparedStatements(30); // because preparing scripts for execution is expensive
sandbox.setExecutor(Executors.newSingleThreadExecutor());
     
sandbox.eval("var o={}, i=0; while (true) {o[i++]='abc';};");

This code will raise a ScriptCPUAbuseException.

The sandbox beautifies the JavaScript code for this and injects additional statements into the submitted code. It is thus possible that the original line numbers from the submitted JS code are not preserved. To debug the code, which is generated by the sandbox, activate its debug mode as follows using a log4j.properties file (see log4j.properties):

log4j.logger.delight.nashornsandbox.NashornSandbox=DEBUG

This will output the generated JS on the console as follows:

--- Running JS ---
var \__it = Java.type('delight.nashornsandbox.internal.InterruptTest');var \__if=function(){\__it.test();};
while(true) {__if();
  i = i+1;
}
--- JS END ---

The sandbox also allows precompiling frequently used scripts. Using a precompiled script can substantially increase execution times.

NashornSandbox sandbox = NashornSandboxes.create();
CompiledScript script = sandbox.compile("1 + 1");
int result1 = (int) sandbox.eval(script);
int result2 = (int) sandbox.eval(script);

Maven

Just add the following dependency to your projects.

<dependency>
    <groupId>org.javadelight</groupId>
    <artifactId>delight-nashorn-sandbox</artifactId>
    <version>[insert latest version]</version>
</dependency>

Note that up to version v.0.1.31 the library would only work with Java versions lower than 13. To make the library work with Java version 13 and above, please use a library version 0.2.0+. The compatibility with v0.2.0 with lower versions of Java is still experimental. If you encounter issues, specifically in Java 1.8 please use a 0.1.x version (and please report any issues).

This artifact is available on Maven Central.

Maven Central

If you are looking for a JAR with all dependencies, you can also download it from here.

Contributors

Eduardo Velasques: API extensions to block/allow Rhino system functions; Capability to block/allow variables after Sandbox has been created.

Marcin Gołębski: Major refactoring and performance improvements. Among other things improved the performance for JS evaluation and better handling of monitoring for threads for possible CPU abuse (#23).

Marco Ellwanger: Initial support for GraalJS engine by implementing sandbox implementation backed by GraalJS.

Olivier Bourgain: Detection for JDK version and ability to use standalone Nashorn for JDK versions in which it is not included.

Version History

  • 0.4.2: Ensure compatibility with Java 17
  • 0.4.0: Upgrade to Java 20
  • 0.3.2: Updating JSBeautifier dependency (PR #143 by davejbur)
  • 0.3.1: Protect against RegEx attacks in sanitising script input by PR #139
  • 0.3.0: Creating a wrapper for Script Context to be passed to eval to avoid accidental exposure. Resolves Issue #134
  • 0.2.5: Support for pre-compiled scripts (PR #119 by geoffreyharding]
  • 0.2.4: Increased resiliency for killing threads under high load (PR #118 by tellmewhattodo)
  • 0.2.0: Dynamically detects what version of the JDK the library is run with, and will either use the included Nashorn version or use Nashorn dependency (Issue #109, PR #101).
  • 0.1.32: Defaulted allowNoBraces to true since the check easily leads to false positives (Issue #102 and Issue #104)
  • 0.1.28: Upgraded JS Beautify version to 1.9.0 to address failing security checks (Issue #93)
  • 0.1.27: Fix bug that Nashorn Sandbox does not guarantee that scripts will be stopped if they consume too much memory or CPU time (PR #96 by jerome-baudoux)
  • 0.1.25: Graal JS sandbox capabilities have been moved to delight-graaljs-sandbox repository.
  • 0.1.23: Initial support for Graal JS (PR #87 by mellster2012)
  • 0.1.22: Fixing issue with injection of if statement in certain situations (PR #82 by foxep2001); Support for JVMs that do not support ThreadMXBean (PR #84 by amoravec)
  • 0.1.21: Fixing executor thread not set after ms - intermittent issue # 75 by pradeepKaatnam
  • 0.1.20: Implementing protection for security issue # 73 as suggested by amlweems
  • 0.1.19: Performance improvement for beautification PR #71 by turbanoff
  • 0.1.18: Fixing issue #66 with PR #69 by everestbt
  • 0.1.17: Improved way bindings are handled (see PR #68 by everestbt); Fixing issue #66
  • 0.1.16: Removing tools.jar dependency (see issue # 62)
  • 0.1.15: Allowing to inject custom cache for secure JS (see PR #59); Preventing the use of --no-java engine parameter (see issue #57)
  • 0.1.14: Fixed bug that ThreadMonitor waits for too long sometimes (see PR #56 by cmorris)
  • 0.1.13: Added support for providing Bindings for evaluating scrips (see PR #44 by Frontrider); Improving way access to global functions such as exit is blocked; Allowing for|while|do when they are given in quoted strings in JavaScript (see issue #47).
  • 0.1.12: Adding capability for calling Invocable:invoke (see PR #42 from escitalopram); Fixing typos in method signatures (see PR #41 by Sina)
  • 0.1.11: Added support for custom parameters in creating Nashorn Script engine (see issue #40).
  • 0.1.10: Added createBindings to the API to allow overriding global properties (see PR #39 by Srinivasa Chintalapati)
  • 0.1.9: Fixed bug #36
  • 0.1.8: Fixed that do, while and for in comments might cause BracesExceptions (see bug #34)
  • 0.1.7: Used webjar dependency for BeautifyJS and slf4j as logging dependency (PR #35 by thjaeckle); Updated license (see bug #32)
  • 0.1.6: Fixing bug that monitor checking for CPU abuses would hang when it encountered monitor.wait(0) (see issue 30)
  • 0.1.5: Fixing bug #28 with PR 29 by srinivasarajuch - added support for evaluation JS with specific ScriptContext
  • 0.1.4: Fixing bug #27
  • 0.1.3: Improving regex for interrupt injections (PR 26), cleaning up code for obtaining JSBeautifier instance (PR 25)
  • 0.1.2: Improving way JsBeautifier instance is obtained (PR 24)
  • 0.1.1: Making all fields in NashornSandboxImpl protected rather than private (see issue #19)
  • 0.1.0: Major rework and performance improvements implemented by Marcin Gołębski (PR 23)

Further Documentation

delight-nashorn-sandbox's People

Contributors

amoravec avatar davejbur avatar dependabot[bot] avatar eduveks avatar everestbt avatar geoffreyharding avatar happyfacade avatar javadelight avatar kumako avatar mellster2012 avatar mgolebsk avatar mxro avatar obourgain avatar philipborg avatar sinaa avatar tangrammer avatar thjaeckle avatar triniticloud avatar turbanoff avatar vmichalak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delight-nashorn-sandbox's Issues

Missing artifact com.sun:tools:jar:1.4.2 on Java 10

Max,

building a project with proxy-vole library which has switched from javadelight-rhino-sandbox to javadelight-nashorn-sandbox recently, I get above error message on Maven (m2e) with Java 10. That's due to Java 10 has no file tools.jar any longer (Java 8 has this system dependency).

  1. Does nashorn-sandbox need this dependency?
  2. What's with updating this fairly updated version 1.4.2 to any actual one?

Your current dependency in POM:

  <dependency>
  	<groupId>com.sun</groupId>
  	<artifactId>tools</artifactId>
  	<version>1.4.2</version>
  	<scope>system</scope>
  	<systemPath>${java.home}/../lib/tools.jar</systemPath>
  </dependency>

Proxy-vole also has implemented slf4j api with latest version, one thing I've read here is under discussion of removing. I'd stay with it... ;-)

Kind regards
Guido

Move methods to builder / throws exception

Hi all,

First of all, thanks for your work on this library. I found some advice on how to make a robust sandbox for Nashorn here.

On the NashornSandboxImpl class, all allowXXXFunction() methods cannot be called after first eval(). To simplify library usage it could be cool to move theses methods to a builder or, at least, throws an exception to alert user of his mal-usage.

When we reach a consensus, if anyone are ok, I will implement it.

Performance improvements

I would like to pre-compile all the JS, cache them and evaluate pre-compiled versions to improve performance.
can you publish a sample ?

Thanks a lot!

Multi-thread environment question

Hi,

In my program I evaluate JavaScript snippets parsed from html pages.
My aim is to detect JavaScript redirection.
My question is:
should I create sandbox for every thread?
NashornSandbox sandbox = NashornSandboxes.create();

In case I can use the same sandbox with different contexts which executor should I use in case I want to limit CPU usage?
sandbox.setExecutor(?);
I believe single thred executor cannot be used for multi-threaded environment.

Security

Execute this code:

nashornSandbox.eval("exit();");

And the result will be SAYONARA!

To prevent this with some investigations I made this script to "pre-eval" and jail:

nashornSandbox.eval("\n" +
                "quit = function() {};\n" +
                "exit = function() {};\n" +
                "\n" +
                "print = function() {};\n" +
                "echo = function() {};\n" +
                "\n" +
                "readFully = function() {};\n" +
                "readLine = function() {};\n" +
                "\n" +
                "load = function() {};\n" +
                "loadWithNewGlobal = function() {};\n" +
                "\n" +
                "Java = null;\n" +
                "org = null;\n" +
                "java = null;\n" +
                "com = null;\n" +
                "sun = null;\n" +
                "net = null;\n" +
                "\n" +
                "$ARG = null;\n" +
                "$ENV = null;\n" +
                "$EXEC = null;\n" +
                "$OPTIONS = null;\n" +
                "$OUT = null;\n" +
                "$ERR = null;\n" +
                "$EXIT = null;\n" +
                "");

Will be great if this project brings this by default.

Guava dependency

After I added the nashorn-sandbox to my pom, other features that uses some google APIs stopped working with this exception:

As far as I can tell, delight-nashorn-sandbox depends on a pretty old guava version, pre guava 15, released in 2013. For instance, guava 19 was released Dec 2015.

I don't know how to discover which dependency needs to be updated as this project's pom.xml does not declare a guava dependency, but is it possible to track this and use a more up to date guava?

Thanks!

importClass is not defined

When I use this sandbox, load mozilla_compat.js, and use importClass to import java class, it tells me "importClass" is not defined.
there is code:

        NashornSandbox sandbox = NashornSandboxes.create();
        sandbox.setMaxCPUTime(1000*30);
        sandbox.setMaxMemory(50*1024*1024);
        sandbox.allowNoBraces(false);
        sandbox.setMaxPreparedStatements(30); // because preparing scripts for execution is expensive
        sandbox.setExecutor(Executors.newSingleThreadExecutor());
        String loadJS ="load('nashorn:mozilla_compat.js'); importClass(java.lang.String);";
        String loadClass = "; ";
        String funcJs = loadJS + loadClass+ "function execute(data){  var o={}, i=0; while (true) {o[i++]='abc';} return JSON.stringify(o);}";
        sandbox.eval(funcJs);

there is error:
Exception in thread "main" javax.script.ScriptException: ReferenceError: "importClass" is not defined in at line number 3
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:454)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:406)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:402)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
at delight.nashornsandbox.internal.EvaluateOperation.executeScriptEngineOperation(EvaluateOperation.java:47)
at delight.nashornsandbox.internal.JsEvaluator.run(JsEvaluator.java:54)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: :3 ReferenceError: "importClass" is not defined
at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57)
at jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:319)
at jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:291)
at jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:278)
at jdk.nashorn.internal.runtime.ScriptObject.noSuchProperty(ScriptObject.java:2357)
at jdk.nashorn.internal.runtime.ScriptObject.noSuchMethod(ScriptObject.java:2283)
at jdk.nashorn.internal.runtime.ScriptObject.findGetMethod(ScriptObject.java:1954)
at jdk.nashorn.internal.objects.Global.findGetMethod(Global.java:2170)
at jdk.nashorn.internal.runtime.ScriptObject.lookup(ScriptObject.java:1820)
at jdk.nashorn.internal.runtime.linker.NashornLinker.getGuardedInvocation(NashornLinker.java:104)
at jdk.nashorn.internal.runtime.linker.NashornLinker.getGuardedInvocation(NashornLinker.java:98)
at jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker.getGuardedInvocation(CompositeTypeBasedGuardingDynamicLinker.java:176)
at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:154)
at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:253)
at jdk.nashorn.internal.scripts.Script$76$^eval_.:program(:3)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:449)
... 9 more

i don't know why, is there anyone can help?

how about other "bad" cases?

...like:

while(true);

or:

while(true) x++;

does your sandbox handle those as well? I noticed you add function checking for thread interruption on every ";" and every ") {" but none of this will work in cases above...

All JARs with one click!

The JVM can run inside others technologies like NodeJS, PHP, Python, Ruby, etc...

Is a nightmare to a developer of other technologies work with Maven, because Maven is the worst tool compared with others, because is the more complex. For example, NPM, Artisan, EGG, GENS and etc... are much much much more easy to work than Maven.

I know the build in Java is more complex, but is too complex like .Net, and in .Net the NuGets is much more simple than the Maven!

I don't understand why many Java projects don't have the jars easy to download!

All the XTEND projects to instal only has the Maven instructions, is ridiculous!

And to not say about people that only use the JRE or even don't have the Maven installed will be forced to install only to build a little JAR. Think in time spent only to build a simple JAR.

Like the Hibernate projects has a ZIP with all JARs and dependencies to download and start to play! Is very very simple!

I strongly suggest to more people can use this project you can put the main Jar and the dependencies of org.eclipse.xtext.***.jar easy to download.

Is just a suggest that I think is very useful to non Java pros and non Maven experts.

Eval with ScriptContext ignores settings

As with issue #67, when a ScriptContext is used it will ignore the settings chosen.

This is exposed by a currently ignored test: testQuitWithScriptContext()

My only proposed solution at the moment is to disallow this method with an UnsupportedOperationException, this does create backwards compatibility issues but with the current implementation it is unclear that this will be the result.

Security contact?

Is there some way to contact you privately regarding security issues?

Project license, declared dependencies

Hi there, I just stumbled upon this project and it's functionality is looking really great. Exactly what I was looking for in order to safely execute JavaScript from the JVM.

I don't want to be a smart-arse, I just want to point out some potentially legal and dependency issues of the project, hope you are not offended.

  • the LICENSE.TXT must contain the license texts, otherwise I fear it is not valid - for a dual license both license texts should be there, e.g. https://choosealicense.com is a good resource for templates and choosing a license (note that both MIT and ASL2.0 license have same placeholders to fill in with year + name of copyright holder)
  • your pom.xml even defines 3 licenses (MIT, ASL2.0 and GPL) - I'm not an expert but I am not sure if GPL is compatible to both ASL2.0 and MIT .. is GPL intended? every user of this library would also have to make his source-code GPL (which would lead to that a none GPL project cannot legally use it)
  • the sources include the "beautify.js" and "beautify.min.js" which is a problem as you redistribute this library. https://github.com/beautify-web/js-beautify has MIT license, so you must include its copyright notice if you re-distribute it (otherwise you violate the MIT license)
    • an easy solution would be to simply add the webjar dependency in Maven:
    <dependency>
     <groupId>org.webjars.bower</groupId>
     <artifactId>js-beautify</artifactId>
     <version>1.6.12</version>
    </dependency>
    • webjar scripts can be loaded in Java by e.g.: InputStream is = getClass().getResourceAsStream("/META-INF/resources/webjars/js-beautify/1.6.12/js/lib/beautify.js");
  • the project has a dependency for log4j (which is a concrete log-impl) - it should use SLF4J-API instead and not provide a log4j.properties in its sources, otherwise I as user of this library will be forced to use log4j and the provided logger config
  • I see you are using OSGi - is there a reason to have a package import of "org.junit"? that would lead to that I would have to provide junit in my OSGi container during runtime ..

Sorry that I don't provide a PR fixing all this, but the license should be chosen by you guys.
I would really love to use this library and am happy to give advise if you want to.

Unable to block access to NashornScriptEngine

Nashorn exposes an instance of NashronScriptEngine through the engine property.

This allows executing arbitrary code as follows:

sandbox.eval("delete this.engine; this.engine.factory.scriptEngine.compile('var File = Java.type(\"java.io.File\"); File;').eval()");

The test case for this is defined here: Test Engine

Workaround:

It is suggested that this can be resolved when using a SecurityManager.

Ability to provide arguments to getScriptEngine

Would it be possible to extend the library, such that it'd be possible to pass arguments to getScriptEngine such as "-strict", "--no-java", "--no-syntax-extensions" ?

It'd be a great help since this library already provides sandboxing features such as CPU limits, etc.

Nashorn Engine is not exit

I set the max cpu time for 10 seconds. After 10 seconds, the execution of my script is not stopped while my %CPU usage is 0.0 (stopped). Can you help me to solve this issue, please?

Script failing with invalid syntax error

Below script execution is failing

function preProcessor()
{
serviceInputParams.put("inputparam", " for ");
}
preProcessor();

Error :
JavaScript. Cause: No block braces after function|for|while|do. Found [for ");\n}
\npreProcessor();

Looks like "for" keyword is identified even it is code.

Insertion of intCheckForInterruption et al. at the top breaks the line numbers in stacktraces

The evaluated JavaScript code is prefixed with some variable declarations and the definition of the intCheckForInterruption function. This moves the original code several lines down. Stacktraces generated by running the code will point to the wrong line.

I fixed this locally by removing all the new lines in NashornSandBoxImpl.eval.run
Now the extra code is added to the first line of original JavaScript code.

This is important to report the error back to the submitter of the code (who is not aware of all fiddling to make the code interruptible)

this.scriptEngine.getContext() gives NullPointerException

I just tried the new setWriter function and it does not seem to work. On line 420 of NashornSanboxImpl we have

ScriptContext _context = this.scriptEngine.getContext();

which throws a java.lang.NullPointerException for me.
Before I call it I do nothing strange with the sandbox, just create it and set the executor. It does not matter if I allowPrintFunctions before or not.

dependency problem

I wanted to use delight-nashorn-sandbox in Scala, but it
crashes due to the "org.eclipse.xtend#org.eclipse.xtend.lib.gwt;2.8.3"
as shown in the error below.

I used this in my project.
libraryDependencies += "org.javadelight" % "delight-nashorn-sandbox" % "0.0.8"

I get this error:

Error:Error while importing SBT project:
...

[warn] 	:: org.eclipse.xtend#org.eclipse.xtend.lib;2.8.3: not found
[warn] :: org.eclipse.xtend#org.eclipse.xtend.lib.gwt;2.8.3: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Unresolved dependencies path:
[warn] org.eclipse.xtend:org.eclipse.xtend.lib:2.8.3
[warn] +- org.javadelight:delight-nashorn-sandbox:0.0.8 (/Users/ringo/weblvc/server/mikan-server/build.sbt#L13-22)
[warn] +- mikan:mikan_2.11:1.0-SNAPSHOT
[warn] org.eclipse.xtend:org.eclipse.xtend.lib.gwt:2.8.3
[warn] +- org.javadelight:delight-functional:0.0.10
[warn] +- org.javadelight:delight-async:0.1.0
[warn] +- org.javadelight:delight-nashorn-sandbox:0.0.8 (/Users/ringo/weblvc/server/mikan-server/build.sbt#L13-22)
[warn] +- mikan:mikan_2.11:1.0-SNAPSHOT
[trace] Stack trace suppressed: run 'last :ssExtractProject' for the full output.
[trace] Stack trace suppressed: run 'last :update' for the full output.
[error] (
:ssExtractProject) sbt.ResolveException: unresolved dependency: org.eclipse.xtend#org.eclipse.xtend.lib;2.8.3: not found
[error] unresolved dependency: org.eclipse.xtend#org.eclipse.xtend.lib.gwt;2.8.3: not found
[error] (
:update) sbt.ResolveException: unresolved dependency: org.eclipse.xtend#org.eclipse.xtend.lib;2.8.3: not found
[error] unresolved dependency: org.eclipse.xtend#org.eclipse.xtend.lib.gwt;2.8.3: not found
[error] Total time: 12 s, completed 24/03/2017 1:54:11 PM

See complete log in file:/Users/ringo/Library/Logs/IdeaIC2017.1/sbt.last.log

CPU Restriction is unstable

as I noted in #52 the CPU control method sometimes throws a RuntineException instead of the expected ScriptCPUAbuseException.

It's a rare occasion (The unit tests sometimes fail for no reason), but I can confirm that it can happen, and should be handled.

Remove slf4j from the dependencies

I had some trouble integrating it because of this dependency, and it doesn't really serves any vital purpose.
What it is actually used for, can be substituted with a the default out/err methods, and a boolean flag.

Would make the library more light weight and easier to integrate, with existing systems.

It's a good thing to have a logging library, but here it feels a little overkill.

Restricted to return only one object!

Will be great if possible grab any global variable of the script.

As is possible using the native ScriptEngine of the Nashorn.

Object scriptVar = engine.get("any_variable");

With NashornSandbox this is impossible!

An idea:

nashornSandbox.extract("my_script_var");
nashornSandbox.eval("my_script_var = 1;");
Object myScriptVar = nashornSandbox.get("my_script_var");
nashornSandbox.clean();

With this solution will be able to say first each variable the ScriptEngine inside the thread need to collect in an Map.

And an method to clear the Map to prevent memory usage with trash.

Limiting memory usage

Is there any way to limit the memory usage of Nashorn scripts? Possibly the malicious code may create too much object or a big string that can cause OOM and crash the JVM.

setWriter function removed?

I pushed for a setWriter function that was added but for some reason removed later on in this commit.
7cab5e8
Why? I don't see why that function would cause any harm and it is rather usable. No new functionality has been added to replace it neither as far as I know. @mxro

Executor thread not set after <some value> ms - intermittently

Hey

I am getting into this error Executor thread not set after ms intermittently. I have gone through the code and I came up with a theory where this can happen. This happens when threadToMonitor variable is null in run() method of ThreadMonitor. The reason can be below:

final JsEvaluator evaluator = getEvaluator(op);
executor.execute(evaluator);
evaluator.runMonitor();

Lets say the executor is created with a max pool size of 5 and there are some 100 incoming requests. Here is there is a chance for some requests to be waiting in the queue of executor. Since it is asynchronous, evaluator's runMonitor() method will be called irrespective of whether its corresponding thread is initiated or not. There is wait time of maxCPUTime / MILI_TO_NANO for the threadToMonitor to be set by the executor api. It might be because previously long running threads will get terminated after their maxCPUTime because of threadToMonitor.interrupt(). Here if the thread doesn't goes down after interrupt then it is waiting for 50 more milli seconds and doing a hard shutdown().

So in the case of hard shutdown there is chance of this exception as it is waiting for only maxCPUTime and not for maxCPUTime + 50(the extra time taken for hard shutdown)

synchronized (monitor) {
    if (threadToMonitor == null) {
	monitor.wait(maxCPUTime / MILI_TO_NANO);
    }
}
if (threadToMonitor == null) {
	throw new IllegalStateException("Executor thread not set after " + maxCPUTime / MILI_TO_NANO + " ms");
}

To conclude, in the run() method of ThreadMonitor class, there should be some additional buffer time i.e.

void run() {
    try {
	// wait, for threadToMonitor to be set in JS evaluator thread
	synchronized (monitor) {
		if (threadToMonitor == null) {
			monitor.wait((maxCPUTime + 50) / MILI_TO_NANO);
		}
	}
	if (threadToMonitor == null) {
		throw new IllegalStateException("Executor thread not set after " + maxCPUTime / MILI_TO_NANO + " ms");
	}

Let me know your thoughts.

javax.script.ScriptException when evaluating proxy discovery js

Hello,

When using a proxy discovery library that utilizes nashorn-sandbox, an interrupt function is inserted in a spot that causes the evaluation to fail with a ScriptException. This appears similar to https://github.com/javadelight/delight-nashorn-sandbox/issues/66
but the cause is different.

The proxy detection script:

 
    function FindProxyForURL(url, host)
    {
		var resolved_ip = dnsResolve(host);      // LIMIT DNS LOOKUPS FOR isInNet() FUNCTIONS

		if (isPlainHostName(host))
		return "DIRECT";

		else if  (dnsDomainIs(host, "candy-ito.acme.com.edgesuite.net")
		|| dnsDomainIs(host, "candy-mp.acme.com"))
		return "PROXY http://wbb.proxy.acme.com:8080";

		else if (dnsDomainIs(host, "ripped101.initech.acme.com")
		|| dnsDomainIs(host, "ripened101.initech.acme.com"))
		return "DIRECT";

		else if (dnsDomainIs(host, "whymper-28801.far-west.bluemix.net")
		|| dnsDomainIs(host, "acme.whymperplatform..com"))
		return "PROXY http://matwhymper-proxy-wld.at.acme.com:8080";

		else if (dnsDomainIs(host, "enough.initech.acme.com"))
		return "PROXY http://one.proxy.acme.com:8080";

		else if (dnsDomainIs(host, "gcfppymsu.noc.acme.com")
		|| dnsDomainIs(host, "gcfpbgmsu.noc.acme.com"))
		return "PROXY http://bnoc.proxy.acme.com:8080";

		else if (dnsDomainIs(host, "brand.hoodu.com")
		|| dnsDomainIs(host, "bizness.hoodu.com"))
		return "PROXY one.proxy.acme.com:8080; DIRECT";

		else if (dnsDomainIs(host, ".2bfatness*")
		|| dnsDomainIs(host, "crimsonpermanent.com")
		|| dnsDomainIs(host, "brawndonext.net")
		|| dnsDomainIs(host, "brawndointeractive.com")
		|| dnsDomainIs(host, "brawndo.net"))
		return "DIRECT";   
					  //^^^^^ inserted interupt function breaks the nashorn eval here 

		else if (isInNet(resolved_ip, "192.17.7.3",  "255.255.254.0")
		|| isInNet(resolved_ip, "192.20.7.0",  "255.255.254.0")

		|| isInNet(resolved_ip, "192.67.128.0",  "255.255.192.0")

		|| isInNet(resolved_ip, "192.7.10.12",  "255.255.0.0"))
		return "DIRECT";

		else if (shExpMatch(host, "192.1.1.2"))
		alert("Proxy Test IP Match Successful");

		else if (localHostOrDomainIs(host, "autoproxy.acmedns.net"))
				return "PROXY http://loser.dns.hoodu.com:83";
		else if (localHostOrDomainIs(host, "autotail.acmedns.net"))
				return "PROXY http://loser.dns.hoodu.com:84";

		else 
		return "PROXY one.proxy.acme.com:8080; DIRECT";
	}

It causes the following stack trace.

    javax.script.ScriptException: <eval>:25:1 Expected an operand but found else
     else if (isInNet(resolved_ip, "192.17.7.3", "255.255.254.0") || isInNet(resolved_ip, "192.20.7.0", "255.255.254.0")
     ^ in <eval> at line number 25 at column number 1
        at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470)
        at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:537)
        at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:524)
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:402)
        at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
        at delight.nashornsandbox.internal.EvaluateOperation.executeScriptEngineOperation(EvaluateOperation.java:47)
        at delight.nashornsandbox.internal.NashornSandboxImpl.executeSandboxedOperation(NashornSandboxImpl.java:156)
        at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:146)
        at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:127)
        at com.nvoq.tools.nashorn.JavascriptEvalTest.evalJS(JavascriptEvalTest.java:29)
        at com.nvoq.tools.nashorn.JavascriptEvalTest.main(JavascriptEvalTest.java:48)
     Caused by: jdk.nashorn.internal.runtime.ParserException: <eval>:25:1 Expected an operand but found else
     else if (isInNet(resolved_ip, "192.17.7.3", "255.255.254.0") || isInNet(resolved_ip, "192.20.7.0", "255.255.254.0")
     ^
        at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:294)
        at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:279)
        at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3182)
        at jdk.nashorn.internal.parser.Parser.expression(Parser.java:3282)
        at jdk.nashorn.internal.parser.Parser.expressionStatement(Parser.java:1150)
        at jdk.nashorn.internal.parser.Parser.statement(Parser.java:967)
        at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
        at jdk.nashorn.internal.parser.Parser.functionBody(Parser.java:2901)
        at jdk.nashorn.internal.parser.Parser.functionExpression(Parser.java:2663)
        at jdk.nashorn.internal.parser.Parser.statement(Parser.java:875)
        at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
        at jdk.nashorn.internal.parser.Parser.program(Parser.java:709)
        at jdk.nashorn.internal.parser.Parser.parse(Parser.java:283)
        at jdk.nashorn.internal.parser.Parser.parse(Parser.java:249)
        at jdk.nashorn.internal.runtime.Context.compile(Context.java:1284)
        at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:1251)
        at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:627)
        at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:535)
        ... 10 more

It appears the JsSanitizer regex (([^;]+;){9}[^;]+(?<!break|continue);) ads an interrupt function on a return statement in the middle of a long else if statement. The resulting sanitized javascript fails when evaluated with the nashorn evaluator. Here's the sanitized java script.

var __it=Java.type('delight.nashornsandbox.internal.InterruptTest');var __if=function(){__it.test();};
/*
 **********************************************************
 ** ACME IP space browser autoproxy configuration: one.pac 
 ** Version: 2038.01.19.16_03:14:07
 **********************************************************
 */
function FindProxyForURL(url, host) {__if();
 var resolved_ip = dnsResolve(host); // LIMIT DNS LOOKUPS FOR isInNet() FUNCTIONS
 if (isPlainHostName(host)) return "DIRECT";
 // CHILL FOR VIDEO
 else if (dnsDomainIs(host, "candy-ito.acme.com.edgesuite.net") || dnsDomainIs(host, "candy-mp.acme.com")) return "PROXY http://wbb.proxy.acme.com:8080";
 // initiech
 else if (dnsDomainIs(host, "ripped101.initech.acme.com") || dnsDomainIs(host, "ripened101.initech.acme.com")) return "DIRECT";
 // stark-whymper
 else if (dnsDomainIs(host, "whymper-28801.far-west.bluemix.net") || dnsDomainIs(host, "acme.whymperplatform..com")) return "PROXY http://matwhymper-proxy-wld.at.acme.com:8080";
 // BINOC PROXY DOMAINS
 else if (dnsDomainIs(host, "enough.initech.acme.com")) return "PROXY http://one.proxy.acme.com:8080";
 else if (dnsDomainIs(host, "gcfppymsu.noc.acme.com") || dnsDomainIs(host, "gcfpbgmsu.noc.acme.com")) return "PROXY http://bnoc.proxy.acme.com:8080";
 // MISC PROXY MODE EXCEPTIONS
 else if (dnsDomainIs(host, "brand.hoodu.com") || dnsDomainIs(host, "bizness.hoodu.com")) return "PROXY one.proxy.acme.com:8080; DIRECT";
 // acme ENTERPRISE DIRECT-MODE DOMAIN EXCEPTIONS
 else if (dnsDomainIs(host, ".2bfatness*") || dnsDomainIs(host, "crimsonpermanent.com") || dnsDomainIs(host, "brawndonext.net") || dnsDomainIs(host, "brawndointeractive.com") || dnsDomainIs(host, "brawndo.net")) return "DIRECT";__if();
 //^^^^^ inserted interupt function breaks the nashorn eval here 
 else if (isInNet(resolved_ip, "192.17.7.3", "255.255.254.0") || isInNet(resolved_ip, "192.20.7.0", "255.255.254.0")
  // SPECTRE
  || isInNet(resolved_ip, "192.67.128.0", "255.255.192.0")
  // INITECH
  || isInNet(resolved_ip, "192.7.10.12", "255.255.0.0")) return "DIRECT";
 else if (shExpMatch(host, "192.1.1.2")) alert("Proxy Test IP Match Successful");
 else if (localHostOrDomainIs(host, "autoproxy.acmedns.net")) return "PROXY http://loser.dns.hoodu.com:83";
 else if (localHostOrDomainIs(host, "autotail.acmedns.net")) return "PROXY http://loser.dns.hoodu.com:84";
 else return "PROXY one.proxy.acme.com:8080; DIRECT";
}

Here's a simple tester I used.

package com.test.nashorn;

import delight.nashornsandbox.*;
import delight.nashornsandbox.exceptions.ScriptCPUAbuseException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.script.*;

public class JavascriptEvalTest {

	static private final NashornSandbox engine = NashornSandboxes.create();

	public static void main(String[] args) {
		String jsFile = args[0];
		
		String jsContents = "NooP";
		try {

			jsContents = new String(Files.readAllBytes(Paths.get(jsFile)));
			System.out.println("Javascript contents \n\n"+jsContents+"\n\n");
			System.out.println("Eval Javascript !!!!");
			Object ret = JavascriptEvalTest.engine.eval(jsContents); //nashorn sandbox
			System.out.println("Evaled Javascript "+ret);
			
			// Test for the un sandboxed Nashorn
			//ScriptEngine engineNash = new ScriptEngineManager().getEngineByName("nashorn");
			//Object ret =  engineNash.eval(jsContents);
			System.out.println("Evaled Javascript "+ret);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ScriptCPUAbuseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

I've tested this with Java 8 build 172

disableAllClasses crashes interruption handling

If I disable all classes in the classfilter, it crashes the sandbox. I traced it down to this line:

sb.append("var ").append(JS_INTERRUPTED_TEST).append("=Java.type('").append(clazzName).append("');");

causes this crash:
https://gist.github.com/Frontrider/8bdd6785f2ac9eaf8c3ea7bf267ca1ab

A solution, which also increases security:
Bind this variable to the engine context/current binding directly. That should also improve security, by making sure that this class can not be initialized.
I'm also experimenting with a binding class, which can block the script from setting certain variables, and it seems to be working really well. (basically blacklists variable names, so they can not be set by the script)

Exceptions

Hi!

The errors in scripting is not catchable, like:

nashornSandbox.eval("blah_blah_blah();");

None exceptions can be handle!

Maybe a solution like:

nashornSandbox.getException()

Will be very useful!

Is a nightmare working without log of bad coding.

Thank you.

javax.script.ScriptException when eval special js

Hi,

I want to eval jsonata.js by NashornSandbox(version is 0.1.16). Jsonata.js ie write by es6, jdk8 no full support es6, so i use jsonata-es5.js to test, but still hava problem. It is ok if only use jdk8.

jsonata-es5.zip

only jdk8

        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
        NashornScriptEngine engine = (NashornScriptEngine) factory.getScriptEngine();

        Invocable inv = (Invocable) engine;
        FileReader jsonata = new FileReader(Demo.class.getResource("/jsonata-es5.js").getFile());
        engine.eval(jsonata);
        String sample = FileUtils.readFileToString(new File(Demo.class.getResource("/sample.json").getFile()), "UTF-8");
        engine.put("input", sample);
        Object inputjson = engine.eval("JSON.parse(input);");
        String expression = "Address.City";  // JSONata expression
        Object expr = inv.invokeFunction("jsonata", expression);
        Object resultjson = inv.invokeMethod(expr, "evaluate", inputjson);
        engine.put("resultjson", resultjson);
        Object result = engine.eval("JSON.stringify(resultjson);");
        System.out.println(result);

use NashornSandbox

  NashornSandbox sandbox = NashornSandboxes.create();
        try {
            sandbox.setMaxCPUTime(6000);
            sandbox.setMaxMemory(5000*1024);
            sandbox.allowNoBraces(true);
            sandbox.allowExitFunctions(true);
            sandbox.allowGlobalsObjects(true);
            sandbox.allowLoadFunctions(true);
            sandbox.allowPrintFunctions(true);
            sandbox.allowReadFunctions(true);
            sandbox.setMaxPreparedStatements(10000);
            sandbox.setExecutor(Executors.newSingleThreadExecutor());
            String jsonata = FileUtils.readFileToString(new File(NashornSandboxDemo.class.getResource("/jsonata-es5.js").getFile()),"UTF-8");
            sandbox.eval(jsonata);
            String expression = "Address.City";  // JSONata expression
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sandbox.getExecutor().shutdown();
        }

sample.json

{
  "FirstName": "Fred",
  "Surname": "Smith",
  "Age": 28,
  "Address": {
    "Street": "Hursley Park",
    "City": "Winchester",
    "Postcode": "SO21 2JN"
  },
  "Phone": [
    {
      "type": "home",
      "number": "0203 544 1234"
    },
    {
      "type": "office",
      "number": "01962 001234"
    },
    {
      "type": "office",
      "number": "01962 001235"
    },
    {
      "type": "mobile",
      "number": "077 7700 1234"
    }
  ],
  "Email": [
    {
      "type": "work",
      "address": ["[email protected]", "[email protected]"]
    },
    {
      "type": "home",
      "address": ["[email protected]", "[email protected]"]
    }
  ],
  "Other": {
    "Over 18 ?": true,
    "Misc": null,
    "Alternative.Address": {
      "Street": "Brick Lane",
      "City": "London",
      "Postcode": "E1 6RF"
    }
  }
}

error stack

javax.script.ScriptException: <eval>:131:26 Expected : but found (
     var operators = {__if();
                          ^ in <eval> at line number 131 at column number 26
	at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:467)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:534)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:521)
	at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399)
	at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at delight.nashornsandbox.internal.EvaluateOperation.executeScriptEngineOperation(EvaluateOperation.java:47)
	at delight.nashornsandbox.internal.JsEvaluator.run(JsEvaluator.java:54)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: jdk.nashorn.internal.runtime.ParserException: <eval>:131:26 Expected : but found (
     var operators = {__if();
                          ^
	at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:292)
	at jdk.nashorn.internal.parser.AbstractParser.error(AbstractParser.java:277)
	at jdk.nashorn.internal.parser.AbstractParser.expectDontAdvance(AbstractParser.java:348)
	at jdk.nashorn.internal.parser.AbstractParser.expect(AbstractParser.java:335)
	at jdk.nashorn.internal.parser.Parser.propertyAssignment(Parser.java:2297)
	at jdk.nashorn.internal.parser.Parser.objectLiteral(Parser.java:2155)
	at jdk.nashorn.internal.parser.Parser.primaryExpression(Parser.java:1988)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2511)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.variableStatement(Parser.java:1088)
	at jdk.nashorn.internal.parser.Parser.statement(Parser.java:884)
	at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
	at jdk.nashorn.internal.parser.Parser.functionBody(Parser.java:2901)
	at jdk.nashorn.internal.parser.Parser.functionExpression(Parser.java:2663)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2506)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.variableStatement(Parser.java:1088)
	at jdk.nashorn.internal.parser.Parser.statement(Parser.java:884)
	at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
	at jdk.nashorn.internal.parser.Parser.functionBody(Parser.java:2901)
	at jdk.nashorn.internal.parser.Parser.functionExpression(Parser.java:2663)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2506)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.expression(Parser.java:3282)
	at jdk.nashorn.internal.parser.Parser.primaryExpression(Parser.java:1992)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2511)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.expression(Parser.java:3282)
	at jdk.nashorn.internal.parser.Parser.expressionStatement(Parser.java:1150)
	at jdk.nashorn.internal.parser.Parser.statement(Parser.java:967)
	at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
	at jdk.nashorn.internal.parser.Parser.functionBody(Parser.java:2901)
	at jdk.nashorn.internal.parser.Parser.functionExpression(Parser.java:2663)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2506)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.arrayLiteral(Parser.java:2090)
	at jdk.nashorn.internal.parser.Parser.primaryExpression(Parser.java:1986)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2511)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.propertyAssignment(Parser.java:2301)
	at jdk.nashorn.internal.parser.Parser.objectLiteral(Parser.java:2155)
	at jdk.nashorn.internal.parser.Parser.primaryExpression(Parser.java:1988)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2511)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.argumentList(Parser.java:2588)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2394)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.expression(Parser.java:3282)
	at jdk.nashorn.internal.parser.Parser.returnStatement(Parser.java:1565)
	at jdk.nashorn.internal.parser.Parser.statement(Parser.java:908)
	at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
	at jdk.nashorn.internal.parser.Parser.functionBody(Parser.java:2901)
	at jdk.nashorn.internal.parser.Parser.functionExpression(Parser.java:2663)
	at jdk.nashorn.internal.parser.Parser.memberExpression(Parser.java:2506)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2372)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.assignmentExpression(Parser.java:3353)
	at jdk.nashorn.internal.parser.Parser.argumentList(Parser.java:2588)
	at jdk.nashorn.internal.parser.Parser.leftHandSideExpression(Parser.java:2375)
	at jdk.nashorn.internal.parser.Parser.unaryExpression(Parser.java:3147)
	at jdk.nashorn.internal.parser.Parser.expression(Parser.java:3282)
	at jdk.nashorn.internal.parser.Parser.expressionStatement(Parser.java:1150)
	at jdk.nashorn.internal.parser.Parser.statement(Parser.java:967)
	at jdk.nashorn.internal.parser.Parser.sourceElements(Parser.java:773)
	at jdk.nashorn.internal.parser.Parser.program(Parser.java:709)
	at jdk.nashorn.internal.parser.Parser.parse(Parser.java:283)
	at jdk.nashorn.internal.parser.Parser.parse(Parser.java:249)
	at jdk.nashorn.internal.runtime.Context.compile(Context.java:1286)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:1253)
	at jdk.nashorn.internal.runtime.Context.compileScript(Context.java:625)
	at jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:532)
	... 9 more

Error on evaluating code starting with "do"

When a sandbox instance is created and it disallows no-braces, it throws an exception when the JS code to evaluate starts with any of { function, for, while, do }. Basically, the exception's stacktrace says:

Exception in thread "main" delight.nashornsandbox.exceptions.BracesException: No block braces after function|for|while|do
	at delight.nashornsandbox.internal.JsSanitizer.checkBraces(JsSanitizer.java:177)
	at delight.nashornsandbox.internal.JsSanitizer.secureJs(JsSanitizer.java:220)
	at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:129)
	at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:104)
        ...

It looks like the block braces pattern matching makes it fail whenever the text starts with do. This code can reproduce the issue:

public static void main(String[] args) throws ScriptException {
        NashornSandbox sandbox = NashornSandboxes.create();
        sandbox.setMaxCPUTime(100);
        sandbox.setMaxMemory(1000 * 1000);
        sandbox.allowNoBraces(false);
        ExecutorService executor = Executors.newSingleThreadExecutor();
        sandbox.setExecutor(executor);
        Boolean done = (Boolean) sandbox.eval("done = false;");
        System.out.println(done);
}

question on argument passing

How do I pass an argument to a function using a sandbox?

With the ScriptEngine, I had something like:

val engine = new ScriptEngineManager().getEngineByName("nashorn")
val invocable = engine.asInstanceOf[Invocable]
engine.eval(theJavaScript)
invocable.invokeFunction("filter", data)

where theJavaScript = "function filter(data) { ... }"

How to I do the same within a sandbox?

val sandbox = NashornSandboxes.create
sandbox.eval(theJavaScript)
// then how do I run "filter" with my data, or pass data to theJavaScript

Failed to restrict the cpu and memory utilization for few scenarios

Hi,

We have identified few scenarios where this library is failing to control the usage.
// Scenario 1:
function main(){
for(var i=0;i<2;i++)
logger.debug("loop cnt-"+i);
}
function main2(){
}
main();

//Scenario 2:
function main(){
logger.debug("... In fun1()....");
for(var i=0;i<2;i++)//{
logger.debug("loop cnt-"+i);
}
main();

//Scenario 3:

//simple do-while loop for demo
function loopTest(){
var i=0;
do{
logger.debug("loop cnt="+(++i));
}while(i<11)
}
loopTest();

//Scenario 4:

if(srctable.length) srctable.length = 0;__if();
else {
for(var key in srctable) {__if();
delete srctable[key];
}
}

All the above scenarios can be easily addressed if apply JSLint/JSHint/ESLint kind of JS libraries. Can you please check any other possibilities here.

Runtime exception on setting cpu and memory restrictions.

I am consuming this library in a servlet container and it is always throwing the below error on call.

java.lang.RuntimeException: javax.script.ScriptException: SyntaxError: empty range in char class in at line number 1
at delight.nashornsandbox.internal.JsSanitizer.assertScriptEngine(JsSanitizer.java:124)
at delight.nashornsandbox.internal.JsSanitizer.(JsSanitizer.java:114)
at delight.nashornsandbox.internal.NashornSandboxImpl.getSanitizer(NashornSandboxImpl.java:172)
at delight.nashornsandbox.internal.NashornSandboxImpl.eval(NashornSandboxImpl.java:117)

sandbox = NashornSandboxes.create();
sandbox.setMaxCPUTime(100);
sandbox.setMaxMemory(50 * 1024);
sandbox.allowNoBraces(false);
sandbox.setMaxPerparedStatements(30); // because preparing scripts for
// execution is expensive
sandbox.setExecutor(Executors.newSingleThreadExecutor());

in servlet doGet () {


sandbox.eval("function callMe() { return 42; };");
final Object _get = sandbox.get("callMe");

}

ScriptContext support for nashorn

Hi,

Currently, this library is providing option to set java object as a JS global variable. It is not giving an option to set ScriptContext, which is very useful feature form nashorn library to scoping the script execution as below

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");

// define a different script context
ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);

    // set the variable to a different value in another scope
    engineScope.put("x", "world");

    // evaluate the same code but in a different script context (x = "world")
    engine.eval("print(x)", newContext);

It would be very helpful if you expose the option to set the script context

while(true){}; causes intermittent hangs

Hello,

I am using version 0.1.4 of the library and seeing intermittent hangs when using while(true){}; as the input javascript. Here is a test case that reproduces the problem:

  @Test
  public void testIsMatchCpuAbuseDirect() {
    String js = "while (true) {};";
    for (int i = 0; i < 1000; i++) {
      System.out.println("i = " + i);
      NashornSandbox sandbox = NashornSandboxes.create();
      sandbox.setMaxCPUTime(100); // in millis
      sandbox.setMaxMemory(1000 * 1000); // 1 MB
      sandbox.allowNoBraces(false);
      sandbox.setMaxPerparedStatements(30); // because preparing scripts for execution is expensive
      sandbox.setExecutor(Executors.newSingleThreadExecutor());
      Exception exp = null;
      try {
        Object result = sandbox.eval(js);
      } catch (Exception e) {
        exp = e;
      }
      Assert.assertNotNull(exp);
    }
  }

Also worth noting that the test case completes with successfully if the script is changed to: var o={}, i=0; while (true) {o[i++]='a';};

Would appreciate any help on the issue.

Eval with bindings ignoring allowExitFunctions(false) settings

While trying to wire this up I found an issue with allowExitFunctions(false). When this is set and then eval(String js,Bindings bindings) is called, for example for the script "quit()" it will exit the JVM, counterposed to the intent of the setting.

This appears to be due to the bindings overwriting the original settings. I am not very familiar with Nashorn so my assumptions of the impact of Bindings and the persistence of these methods could be false. For usability I believe it would be helpful that, regardless of Bindings the settings are applied.

Production ready?

We want to allow our users to call javascript code when a particular event occurs, the user-generated code must be sandboxed and run safely. Can we safely use delight-nashorn-sandbox in production?

Also it would be great if you could add a license for the project.

Missing dependency on delight-async

got interested in this and tried to compile, but there is something wrong with the dependencies. Where can I find

<dependency>
    <groupId>org.javadelight</groupId>
    <artifactId>delight-async</artifactId>
    <version>0.0.9</version>
</dependency>Where can I find

or has this been replaced with something else?

--Sebastian

Bug in ThreadMonitor that can cause it to wait unnecessarily

I had noticed in some stress testing that sometimes the call to execute a function would take the maximum CPU limit time. I tracked it down to an issue in ThreadMonitor in the call to wait on the monitor object. It's possible that the threadToMonitor was already set and the monitor notification sent. In that case, the monitor wait goes to the maximum value for the cpu time limit.

The fix is pretty simple. You simply need to check if the threadToMonitor is not null in the synchronized block, but before the wait, and if it's not null, skip the wait. I can submit a pull request with the fix if that will help.

Different execution outcome between the Sandbox and Nashorn executed directly

Hello again. I'm a bit at loss trying to figure out why the following script executes fine with Nashorn when executed directly, but does not work with the NashornSandbox.

The eval on NashornSandboxes triggers the following exception: javax.script.ScriptException: TypeError: null has no such function "type" in <eval> at line number 1.

Please find below a unit test for this:

  @Test
  public void testMapReduce() throws ScriptException {
    String script = "[1,2,3,4].map(function(n){return n+1}).reduce(function(prev,cur){return prev+cur}, 0)";
    String[] NASHORN_ARGS = {"--no-java", "--no-syntax-extensions"};

    Double nashornResult = (Double) new NashornScriptEngineFactory().getScriptEngine(NASHORN_ARGS).eval(script);
    assertEquals(14, nashornResult.intValue());

    Double sandboxResults = (Double) NashornSandboxes.create(NASHORN_ARGS).eval(script);
    assertEquals(14, sandboxResults.intValue());
  }

Sandbox version this was tried on: 0.1.13

Check new line characters

Last time I did tests I found inconsistencies in the new line character. (making it hard to test)
(also, expect that I redo them again sometime,now with the tested scripts exported into actual js files)

I encountered a possible reason. It probably uses the "line.separator" system property instead of \n. That should be checked.

Exit can be called, if the declared javascript function is called directly.

Based on issue #43, I was trying to implement a special binder class which can execute the pre-compiled script on its own, but doing so had unforeseen consequences.

I was able to exit execution from javascript. The way how these things are sandboxed, might need a review, since this would be a really neat feature, and would make the library more usefull. (basicly acts like a dynamic class)
The current implementation is here:
https://github.com/Frontrider/delight-nashorn-sandbox/blob/8c65508f469556a1553adfa723fe533323cd4000/src/main/java/bindings/DelightedBindings.java

Also fails if I call disableAllClasses on the sandbox before executing it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.