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

Posted

技术标签:

【中文标题】如何在沙箱中使用 Rhino for Java 运行 Javascript?【英文标题】:How can you run Javascript using Rhino for Java in a sandbox? 【发布时间】:2010-09-10 18:29:14 【问题描述】:

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

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

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

基本上,我需要将 javascript 范围设置为仅包含他们需要的内容,而不包含更多内容。

【问题讨论】:

你的意思是说(Javascript using Rhino) for (Java in a sandbox),还是(Javascript using (Rhino for Java)) (in a sandbox)? 【参考方案1】:

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

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

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

详情请阅读 ConfigJSParser.java 和 ConfigJSClassLoader.java 文件:

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

【讨论】:

【参考方案2】:

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

有这个example in the 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();
     
 

【讨论】:

【参考方案3】:

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

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

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

对于数据库限制,您也许可以使用标准的 SQL 用户安全性,但这很弱。否则,您需要提供一个 API 来强制执行您的限制。

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

【讨论】:

【参考方案4】:

我刚刚看到这篇博文似乎对沙盒或多或少有用(不仅仅是 Rhino):

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

【讨论】:

【参考方案5】:

要阻止 Java 类和方法访问,请查看...

http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/

【讨论】:

【参考方案6】:

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

【讨论】:

Rhino 有一个可用的线程库(java.lang.Thread!),并且可以访问文件系统。

以上是关于如何在沙箱中使用 Rhino for Java 运行 Javascript?的主要内容,如果未能解决你的问题,请参考以下文章

Rhino:如何从 Java 调用 JS 函数

如何使用 Rhino Mocks 模拟任意行为?

如何在 Java 程序中调用 Rhino 编译的 JavaScript 方法(类文件)?

使用 Rhino(Mozilla 的 rhino)的优点

如何使用 Rhino 将 Java 类中的方法添加为 Javascript 中的全局函数?

使用 Rhino 代替 ScriptEngine 在 Java 中运行 Javascript 代码