views:

861

answers:

3

I'm looking to run some un-verified scripts (written in a yet-to-be-determined language, but needs to be Java-based, so JRuby, Groovy, Jython, BeanShell, etc are all candidates). I want these scripts to be able to do some things and restricted from doing other things.

Normally, I'd just go use Java's SecurityManager and be done with it. That's pretty simple and lets me restrict file and network access, the ability to shutdown the JVM, etc. And that will work well for the high level stuff I want to block off.

But there is some stuff I want to allow, but only via my custom API/library that I've providing. For example, I don't want to allow direct network access to open up a URLConnection to yahoo.com, but I am OK if it is done with MyURLConnection. That is - there is a set of methods/classes that I want to allow and then everything else I want to be off limits.

I don't believe this type of security can be done with the standard Java security model, but perhaps it can. I don't have a specific requirement for performance or flexibility in the scripting language itself (the scripts will be simple procedural calls to my API with basic looping/branching). So even a "large" overhead that checks a security check on every reflection call is fine by me.

Suggestions?

+2  A: 

Disclaimer: I am not an expert on Java Security APIs, so there may be a better way to do this.

I work for Alfresco, Java-based Open Source Enterprise CMS, and we implemented something similar to what you describe. We wanted to allow scripting, but only to expose a subset of our Java APIs to the scripting engine.

We chose Rhino Engine for JavaScript scripting. It allows you to control which APIs are exposed to JavaScript, which allows us to choose which classes are available, and which are not. The overhead, according to our engineers, is on the order of 10%- not too bad.

In addition to this, and this may be relevant to you as well, on the Java side, we use Acegi (now Spring Security), and use AOP to give role-based control over which methods a certain user can call. That works pretty well for authorization. So in effect, a user accessing our app through JavaScript first has a restricted API available to him in the first place, and then that API can be restricted even further based on authorization. So you could use the AOP techniques to further restrict which methods can be called, thus allowing to expose this in other scripting languages, such as Groovy, etc. We are in the process of adding those as well, having the confidence that our underlying Java APIs protect users from unauthorized access.

Jean Barmash
Thanks - that's really helpful. Btw - the use case for me is to allow people to upload scripts for their load tests to run on http://browsermob.com. I hadn't looked at Rhino, but that sounds like it could work as long as it doesn't allow direct access to the Java APIs like Groovy does.
Patrick Lightbody
Yeah - you have more control there, which is good from security perspective. You may have to create wrappers for certain APIs and then expose those objects. For example, we have a workflow engine, and created a workflow object that we then exposed to JavaScript, which controls what you can do.
Jean Barmash
Quick follow-up: how did you make sure that the Packages variable wasn't accessible? See http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/
Patrick Lightbody
+3  A: 

You may be able to use a custom class loader that does vets linking to classes before delegating to its parent.

You can create your own permissions, check for those in your security sensitive APIs and then use AccessController.doPrivileged to restore appropriate privileges whilst calling the underlying API.

You need to make sure that the scripting engine itself is secure. The version of Rhino in the Sun JDK should be okay, but no guarantees. Obviously you need to make sure everything available to the script is secure.

Tom Hawtin - tackline
Tom - thanks for the tips. Sounds like I also need to research the Java security model a bit more - I wasn't aware of doPriveleged
Patrick Lightbody
A: 

You may be able to use a custom class loader that does vets linking to classes before delegating to its parent.

Interesting. How do I do that ? I mean, how do I install a custom CLassLoader to be used by the script engine ?

Thanks !

David