安全Nashorn JS执行

tom*_*_ma 42 javascript java nashorn

如何使用Java8 Nashorn安全地执行一些用户提供的JS代码?

该脚本扩展了一些基于servlet的报告的计算.该应用程序有许多不同(不受信任)的用户.脚本应该只能访问Java对象和已定义成员返回的Java对象.默认情况下,脚本可以使用Class.forName()(使用我提供的对象的.getClass())实例化任何类.有没有办法禁止访问我没有明确指定的任何java类?

Kon*_*ong 25

我前一段时间在Nashorn邮件列表上问了这个问题:

是否有关于将Nashorn脚本可以创建的类限制为白名单的最佳方法的建议?或者方法与任何JSR223引擎(ScriptEngineManager构造函数上的自定义类加载器)相同?

从Nashorn开发者那里得到了这个答案:

嗨,

  • Nashorn已经过滤了类 - 只有非敏感包的公共类(package.access安全属性中列出的包,也就是'敏感').包访问检查是从无权限上下文完成的.即,只允许从无权限类访问的任何包.

  • Nashorn过滤Java反射和jsr292访问 - 除非脚本具有RuntimePermission("nashorn.JavaReflection"),否则脚本将无法进行反射.

  • 以上两个要求在启用SecurityManager的情况下运行.在没有安全管理器的情况下,上述过滤将不适用.

  • 您可以在全局范围内删除全局Java.type函数和Packages对象(+ com,edu,java,javafx,javax,org,JavaImporter)和/或用您实现的任何过滤函数替换它们.因为,这些是从脚本访问Java的唯一入口点,自定义这些函数=>从脚本过滤Java访问.

  • 有一个未记录的选项(现在只用于运行test262测试)nashorn shell的"--no-java"为您执行上述操作.即,Nashorn不会在全局范围内初始化Java钩子.

  • JSR223不提供任何基于标准的钩子来传递自定义类加载器.这可能必须在(可能的)jsr223的未来更新中解决.

希望这可以帮助,

-Sundar

  • 您可以使用以下命令将`--no-java`(和其他选项)传递给引擎:`final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(new String [] {" - no-java"});` (4认同)
  • 我只是想评论只要loadWithNewGlobal没有被删除,第四种方法也行不通.例如,我可以使用以下代码重新创建Java对象:loadWithNewGlobal({script:"arguments [0] .Java = Java",name:"exploit"},this) (2认同)

mko*_*bit 17

1.8u40中添加,您可以使用它ClassFilter来限制引擎可以使用的类.

以下是Oracle文档中的示例:

import javax.script.ScriptEngine;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

public class MyClassFilterTest {

  class MyCF implements ClassFilter {
    @Override
    public boolean exposeToScripts(String s) {
      if (s.compareTo("java.io.File") == 0) return false;
      return true;
    }
  }

  public void testClassFilter() {

    final String script =
      "print(java.lang.System.getProperty(\"java.home\"));" +
      "print(\"Create file variable\");" +
      "var File = Java.type(\"java.io.File\");";

    NashornScriptEngineFactory factory = new NashornScriptEngineFactory();

    ScriptEngine engine = factory.getScriptEngine(
      new MyClassFilterTest.MyCF());
    try {
      engine.eval(script);
    } catch (Exception e) {
      System.out.println("Exception caught: " + e.toString());
    }
  }

  public static void main(String[] args) {
    MyClassFilterTest myApp = new MyClassFilterTest();
    myApp.testClassFilter();
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例打印以下内容:

C:\Java\jre8
Create file variable
Exception caught: java.lang.RuntimeException: java.lang.ClassNotFoundException:
java.io.File
Run Code Online (Sandbox Code Playgroud)


Tom*_*mas 8

我研究了允许用户在沙盒中编写一个简单脚本的方法,该脚本允许访问我的应用程序提供的一些基本对象(与Google Apps脚本的工作方式相同).我的结论是,使用Rhino比使用Nashorn更容易/更好地记录.您可以:

  1. 定义类快门以避免访问其他类:http://codeutopia.net/blog/2009/01/02/sandboxing-rhino-in-java/

  2. 使用observeInstructionCount限制指令数量以避免重复循环:http://www-archive.mozilla.org/rhino/apidocs/org/mozilla/javascript/ContextFactory.html

但是请注意,对于不受信任的用户来说,这还不够,因为他们仍然可以(偶然或故意)分配大量内存,导致JVM抛出OutOfMemoryError.我还没有找到最后一点的安全解决方案.

  • 问题是如何确保Nashorn,而不是Rhino (2认同)

ccl*_*eve 6

据我所知,你不能沙盒Nashorn.不受信任的用户可以执行此处列出的"Additional Nashorn Built-In Functions":

https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/shell.html

其中包括"退出()".我测试了它; 它完全退出JVM.

(顺便说一下,在我的设置中,全局对象$ ENV,$ ARG不起作用,这很好.)

如果我对此有误,请有人发表评论.


mxr*_*xro 5

您可以非常轻松地创建一个ClassFilter允许对JavaScript中可用的Java类进行细粒度控制的方法.

遵循Oracle Nashorn Docs的示例:

class MyCF implements ClassFilter {
    @Override
    public boolean exposeToScripts(String s) {
      if (s.compareTo("java.io.File") == 0) return false;
      return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

我今天在一个小型图书馆中包含了一些其他措施:Nashorn Sandbox(在GitHub上).请享用!


Ama*_*dan 0

我想说覆盖提供的类的类加载器是控制对类的访问的最简单方法。

(免责声明:我不太熟悉较新的 Java,所以这个答案可能是老式/过时的)