如何在沙箱中使用Rhino for Java运行Javascript?

我们的Java应用程序的一部分需要运行由非开发人员编写的JavaScript。 这些非开发人员正在使用JavaScript进行数据格式化。 (主要是简单的逻辑和string连接)。

我的问题是如何设置这些脚本的执行,以确保脚本错误不会对应用程序的其他部分造成严重的负面影响。

  • 需要防范无限循环
  • 防止产生新的线程。
  • 限制访问服务和环境
    • 文件系统(例如:如果一个心存不满的脚本作者决定删除文件)
    • 数据库(同样东西删除数据库logging)

基本上我需要设置的JavaScript范围只包括他们所需要的,没有更多。

为了防止无限循环,你需要把它放在一个单独的进程,以便它可以被杀死。

为防止创build线程,您需要扩展SecurityManager(默认实现允许不受信任的代码访问非根线程组)。

Java安全性确实允许您阻止访问文件系统。

对于数据库限制,您可能能够使用标准的SQL用户安全性,但这是相当薄弱的。 否则,你需要提供一个强制你的限制的API。

编辑:我应该指出,JDK6提供的Rhino版本已经完成了安全工作,但不包括编译器。

为了防止无限循环,可以在脚本运行时观察指令计数(这仅适用于解释脚本,不适用于编译脚本)。

在Rhino的JavaDocs中有这样的例子来阻止脚本运行超过十秒:

protected void observeInstructionCount(Context cx, int instructionCount) { MyContext mcx = (MyContext)cx; long currentTime = System.currentTimeMillis(); if (currentTime - mcx.startTime > 10*1000) { // More then 10 seconds from Context creation time: // it is time to stop the script. // Throw Error instance to ensure that script will never // get control back through catch or finally. throw new Error(); } } 

我只是跑过这个博客文章,似乎是沙箱或多或less有用(不只是犀牛)有用:

http://calumleslie.blogspot.com/2008/06/simple-jvm-sandboxing.html

如果您只是在寻找纯粹的JavaScript函数,那么下面是一个基于JDKembedded式Rhino库而不导入任何第三方库的解决scheme:

  1. 通过ScriptEngineManager#getEngineFactories查找JavaScript脚本引擎工厂类名
  2. 将脚本引擎工厂类加载到新的类加载器中,其中JavaMembers或其他相关的类将被忽略。
  3. 在加载的脚本引擎工厂调用#getScriptEngine,并在返回的脚本引擎上调用eval脚本。

如果给定脚本包含Java脚本,则类加载器将尝试加载JavaMembers或其他类,并触发类未发现的exception。 这样,恶意脚本将被忽略而不执行。

请阅读ConfigJSParser.java和ConfigJSClassLoader.java文件以获取更多详细信息:

https://github.com/webuzz/simpleconfig/tree/master/src/im/webuzz/config

Javascript是单线程的,不能访问文件系统,所以我不认为你必须担心这些。 我不确定是否有办法设置超时以防止无限循环,但是您总是可以生成执行脚本的(Java)线程,然后在很长时间后终止线程。