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

36
我们的Java应用程序需要运行由非开发人员编写的JavaScript,这些非开发人员使用JavaScript进行数据格式化(主要是简单逻辑和字符串拼接)。
我的问题是如何设置脚本的执行以确保脚本错误不会对应用程序的其余部分产生重大负面影响。
  • 需要防止无限循环
  • 防止生成新线程。
  • 限制对服务和环境的访问
    • 文件系统(例如:如果一个不满意的脚本编写者决定删除文件)
    • 数据库(同样可以删除数据库记录)
基本上我需要设置JavaScript范围,仅包含他们需要的内容,而没有更多。

3
你是说你想要翻译成中文吗?“你是指(使用Rhino的JavaScript)是在(沙盒中的Java),还是(使用(Java的Rhino)的JavaScript)在沙盒中?” - Anderson Green
6个回答

20
为了防止无限循环,您可以在脚本运行时观察指令计数(这仅适用于解释脚本,而不是编译脚本)。
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();
     }
 }

13

10
为了防止无限循环,您需要将它放在单独的进程中,以便可以终止它。
为了防止创建线程,您需要扩展SecurityManager(默认实现允许不受信任的代码访问非根线程组)。
Java安全性确实允许您防止访问文件系统。
对于数据库限制,您可能可以使用标准SQL用户安全性,但这相当薄弱。否则,您需要提供一个API来执行您的限制。
编辑:我应该指出,JDK6提供的Rhino版本已经进行了安全性工作,但不包括编译器。

1

0

如果您仅需要纯JavaScript函数,这里有一个基于JDK嵌入式Rhino库的解决方案,无需导入任何第三方库:

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

如果给定的脚本包含Java脚本,则类加载器将尝试加载JavaMembers或其他类并触发类未找到异常。通过这种方式,恶意脚本将被忽略而不执行。

请阅读ConfigJSParser.java和ConfigJSClassLoader.java文件以了解更多细节:

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


-9
JavaScript是单线程的,无法访问文件系统,所以我认为你不必担心这些。我不确定是否有一种方法可以设置超时来防止无限循环,但你总可以生成一个(Java)线程来执行脚本,然后在一定时间后终止该线程。

11
犀牛 Rhino 可以使用线程库(java.lang.Thread!)并访问文件系统。 - Tom Hawtin - tackline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接