How does one run Java 8's nashorn under a SecurityManager - security

I am looking to sandbox Java 8's Nashorn javascript engine. I've already discovered the --no-java flag, which helps, but I've also found the following link saying that one needs to be "running with SecurityManager enabled": http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-September/002010.html
I haven't found documentation addressing how this is done with Nashorn, so how should this be done safely?

I know you probably don't need that anyway anymore, but for those who got here looking for an easy way to run nashorn in sandbox: if you just want to prevent scripts from using reflection, set up a ClassFilter. This way you can allow to use only SOME of the available classes... or none at all.
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine scriptEngine = factory.getScriptEngine(
new String[] { "--no-java" }, //a quick way to disable direct access to java API
null, //a ClassLoader, let's just ignore it
new ClassFilter() { //this one simply forbids use of any java classes, including reflection
#Override
public boolean exposeToScripts(String string) {
return false;
}
}
);

It is possible to execute scripts using jjs with security manager enabled.
jjs -J-Djava.security.manager myscript.js
or
jjs -J-Djava.security.manager
for interactive mode. Note that if you just use -Djava.security.manager, than that option is processed by jjs tool. To pass option to VM, you've to use -J prefix. This is true of any other JDK bin tool other than the launcher tool "java".

Unlike the java command, it doesn't seem possible to enable a security manager by setting the java.security.manager property on the jjs command line. (This might be a bug.) However, you can call the Java APIs from JavaScript to enable the security manager. In Java, this is
System.setSecurityManager(new SecurityManager());
and in JavaScript/Nashorn it's pretty much the same except you provide fully qualified class names:
java.lang.System.setSecurityManager(new java.lang.SecurityManager())
(Alternatively, you can import the names.) Either you can put this line into your application script, or you can put it into a script that you place on the jjs command line before your application script.
Example:
$ cat userhome.js
print(java.lang.System.getProperty("user.home"))
$ jjs userhome.js
/Users/xyzzy
$ cat secmgr.js
java.lang.System.setSecurityManager(new java.lang.SecurityManager())
$ jjs secmgr.js userhome.js
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "user.home" "read")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)
[...snip...]
It does work to set the policy file on the command line, though:
$ cat all.policy
grant {
permission java.security.AllPermission;
};
$ jjs -Djava.security.policy=all.policy secmgr.js userhome.js
/Users/xyzzy
Or you can just add the equivalent setProperty call before enabling the security manager:
$ cat secmgr.js
java.lang.System.setProperty('java.security.policy', 'all.policy')
java.lang.System.setSecurityManager(new java.lang.SecurityManager())

Related

Error 500 after connecting to Redis in Jmeter

I have a question about Groovy scripting in Jmeter.
I have created a function in Groovy that connects to Redis DB, and the function works as expected.
Afterwards, when from "main" I try to get data, it says that he is not familiar with get from Redis.
My purpose is to create the first function that connects to Redis, the second one that creates Redis key, and the third one to get data using the Redis key.
in the "main" I call connect and it works, but the third one does not work. Is it because the connection is closed?
Not seeing your code it is hard to guess what is wrong, according to the error message jedis variable is not defined in the scope, you are trying to access it. you can try defining it globally like:
def jedis = null; // make "jedis" variable available to all methods
void connect() {
jedis = new Jedis(vars.get('Redis_IP', vars.get('Redis_Port') as int)
}
void somethingElse () {
if (jedis != null) {
log.info(jedis.ping())
}
}
A couple of points to consider:
Don't inline JMeter Variables or Functions into script body, it makes compilation caching feature aimpossible so the overall performance of your code will be lower. Also variables might resolve into something causing script interpretation failure or unexpected behaviour. Either use "Parameters" section or go for code-based equivalents as in my above demo
It is recommended to use JMeter built-in features (or plugins) where possible as even well-behaved Groovy script doesn't perform that fast as "normal" Java code. Check out if Redis Data Set is matching your use case and if it does - simply install it using JMeter Plugins Manager and start using instead of struggling with Groovy.
See JMeter’s Redis Data Set - An Introduction article for step-by-step instructions on the plugin installation and usage

Puppet exception handling?

I was wondering how one would do try/catch/throw type exception handling in a puppet manifest. Here's how I wish puppet would work ...
class simple {
unless ( package { 'simple': ensure => present } ) {
file { '/tmp/simple.txt':
content => template( 'simple/simple.erb' ),
}
}
}
Thanks
I don't think there is an exception handling in a programmatic way you would like in Puppet. If you declare a resource, it is expected that puppet brings your machine to that state (installed package) and if not, it will fail automatically.
One thing that you can do (and I don't recommend) and that is not "puppet way" is following:
Create custom facter (not custom function since it is executed on puppet master and you want this ruby code to be executed on puppet agent)
Since it is plain ruby code in facter, you can have exception handling and all programmatic things. You can install package as unix command from puppet code and have some logic which will, if not installed retrieve some value as fact
You would use this fact value and based on it you would determine if you want to create file or not
Also, if easier, you can write bash script which will do this logic and execute it from puppet using exec resource
Hope it helps.

Nashorn : how to evaluate scripts in scripting mode

Im starting to explore jdk 8 new javascript engine nashorn and wanted to build some automating task scripts. I ve an issue, ive no idea how to evaluate a js file in scripting mode from javascript, using engine.eval() eg .
p.s: im not talking about jjs -scripting which is good but only works one way. I want the other way; make the engine evaluate in scripting mode from java
The easiest way is to add -Dnashorn.args=-scripting to you java command line.
After a lot of head scratching, i came up with a trick where i can actually launch my script's execution through a command line from a hand crafted System Process :
//tricking the nashorn engine with jjs command
public void evalScriptInScriptingMode(String fileName)
{
String[] args = new String[]{"jjs", "-scripting", fileName};
//This class is used to create operating system processes
ProcessBuilder pb = new ProcessBuilder(args);
pb.directory(null);
File log = new File("jjs_log.txt");
int i = 0;
while(log.exists())
{
i++;
log = new File("jjs" + i + "_log.txt");
}
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.appendTo(log));
Process p = null;
try
{
p = pb.start(); //start the process which remains open
}
catch(IOException e)
{
e.printStackTrace();
}
}
You can pass arguments to the script engine via the NashornScriptEngineFactory.
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
new NashornScriptEngineFactory()
.getScriptEngine( "-scripting" )
.eval( "" );
You can also use new NashornScriptEngineFactory().getScriptEngine("-scripting"); which will retrieve a new Nashorn ScriptEngine in scripting mode. This method is slightly better than using a System Process mainly because this automatically adds you classes to the nashorn classpath.
Basically, you can program classes in java and then use'em in javascript. If you do not need to be able to reference your classes in javascript then the System Process should do just fine and there won't be problems, ( if the machine on which this is running has jjs in their classpath )

How do you forbid users from doing evil things in Groovy Scripts?

I'm planning to integrate Groovy Script Engine to my game so it will give the game nice moddability but how do you prevent players from writing evil scripts like deleting all files on C: drive?
Groovy includes library like java.io.File by default so it will be pretty easy to do once they decided to write such scripts.
I guess I can't prevent users from writing something like while(1==1){} but is there anyway to at least not let them allow to delete/modify files or something dangerous for PCs?
There's a blog post by Cedric Champeau on customising the Groovy Compilation process, the second part of it shows how to use SecureASTCustomizer and CompilerConfiguration to limit what Scripts can do (and then has examples of defining your own AST checks for System.exit, etc...
Look into the SecurityContext class.
The Groovy Web Console appears to have already solved this problem, because it won't execute something like System.exit(1). The source code is available on GitHub, so you can see how they did it.
If you're not sure where to start, I suggest getting in touch with the author, who should be able to point you in the right direction.
I know this is a old question. I'm posting this as it might help some people out there.
We needed to allow end-users to upload Groovy scripts and execute them as part of a web application (that does a lot of other things). Our concern was that within these Groovy scripts, some users might attempt to read files from the file system, read System properties, call System.exit(), etc.
I looked into http://mrhaki.blogspot.com/2014/04/groovy-goodness-restricting-script.html but that will not prevent an expert Groovy developer from bypassing the checks as pointed out by others in other posts.
I then tried to get http://www.sdidit.nl/2012/12/groovy-dsl-executing-scripts-in-sandbox.html working but setting the Security Manager and Policy implementation at runtime did not work for me. I kept running into issues during app server startup and web page access. It seemed like by the time the Policy implementation took hold, it was too late and "CodeSources" (in Java-Security-speak) already took its access settings from the default Java policy file.
I then stumbled across the excellent white paper by Ted Neward (http://www.tedneward.com/files/Papers/JavaPolicy/JavaPolicy.pdf) that explained quite convincingly that the best approach (for my use case) was to set the Policy implementation on JVM startup (instead of dynamically later on).
Below is the approach that worked for me (that combines Rene's and Ted's approaches). BTW: We're using Groovy 2.3.10.
In the [JDK_HOME]/jre/lib/security/java.security file, set the "policy.provider" value to "com.yourcompany.security.MySecurityPolicy".
Create the MySecurityPolicy class:
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.util.HashSet;
import java.util.Set;
public class MySecurityPolicy extends Policy {
private final Set<URL> locations;
public MySecurityPolicy() {
try {
locations = new HashSet<URL>();
locations.add(new URL("file", "", "/groovy/shell"));
locations.add(new URL("file", "", "/groovy/script"));
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
#Override
public PermissionCollection getPermissions(CodeSource codeSource) {
// Do not store these in static or instance variables. It won't work. Also... they're cached by security infrastructure ... so this is okay.
PermissionCollection perms = new Permissions();
if (!locations.contains(codeSource.getLocation())) {
perms.add(new AllPermission());
}
return perms;
}
}
Jar up MySecurityPolicy and drop the jar in [JDK_HOME]/jre/lib/ext directory.
Add "-Djava.security.manager" to the JVM startup options. You do not need to provide a custom security manager. The default one works fine.
The "-Djava.security.manager" option enables Java Security Manager for the whole application. The application and all its dependencies will have "AllPermission" and will thereby be allowed to do anything.
Groovy scripts run under the "/groovy/shell" and "/groovy/script" "CodeSources". They're not necessarily physical directories on the file system. The code above does not give Groovy scripts any permissions.
Users could still do the following:
Thread.currentThread().interrupt();
while (true) {} (infinite loop)
You could prepend the following (dynamically at runtime) to the beginning of every script before passing it onto the Groovy shell for execution:
#ThreadInterrupt
import groovy.transform.ThreadInterrupt
#TimedInterrupt(5)
import groovy.transform.TimedInterrupt
These are expalined at http://www.jroller.com/melix/entry/upcoming_groovy_goodness_automatic_thread
The first one handles "Thread.currentThread().interrupt()" a little more gracefully (but it doesn't prevent the user from interupting the thread). Perhaps, you could use AST to prevent interupts to some extent. In our case, it's not a big issue as each Groovy script execution runs in its own thread and if bad actors wish to kill their own thread, they could knock themselves out.
The second one prevents the infinite loop in that all scripts time out after 5 seconds. You can adjust the time.
Note that I noticed a performance degradation in the Groovy script execution time but did not notice a significant degradation in the rest of the web application.
Hope that helps.

Is it possible to automatically preload user classes into the groovy interpreter?

Is there any way to automatically load user classes in the groovy interpreter, the way System.out is automatically loaded (so you don't have to import System.out to use println)? I want to be able to write scripts that employ custom classes and run the scripts in the groovy interpreter without having to import all the classes all the time.
Yep, you just need to create a profile/rc file. Just create a file at ~/.groovy/groovysh.profile and put your imports in there. You'll also want to make sure that any additional classes you want to include are part of your CLASSPATH.
ex: ~/.groovy/groovysh.profile:
import org.apache.commons.lang.StringUtils
println "in groovysh.profile"
Then run groovysh and use a method from StringUtils:
% groovysh
in groovysh.profile
Groovy Shell (1.7.3, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
---------------------------------------------------------------------------------------------------------------------------------
groovy:000> StringUtils.isWhitespace(" ")
===> true
groovy:000>
You can see that the import is in place (and that it also printed out the println I had in the profile. This example will only work if you've got the commons-lang jar file is in your classpath.
See the Groovy Shell page for more details.
Groovy adds some methods to Object, including methods like println and printf that you'd expect on printWriters. They implicitly use System.out. This is actually how groovy makes if feel like System.out is globally available.
If you want to import a set of classes by default, so they can be used without specifying the full package name, Ted's comment about groovysh.profile applies.
However, if you want a specific object, like System.out, global available so its methods can be called without referencing the object, then you can add some dynamic methods to Object. For example, to make the logging methods of the default global JDK logger globally available:
Object.metaClass.info = { String message ->
java.util.logging.Logger.global.info(message)
}
Object.metaClass.warning = { String message ->
java.util.logging.Logger.global.warning(message)
}
Object.metaClass.severe = { String message ->
java.util.logging.Logger.global.severe(message)
}
etc...
Once those methods are applied to the base Object metaClass, any object can call info("message") and have it logged, effectively making Logger.global available in the same way System.out is.

Resources