在 Nashorn 中禁用 ECMAScript 扩展

Disabling ECMAScript extensions in Nashorn

我需要从我的应用程序内部 运行 一个简单的脚本,用户应该能够 enter/modify 这个脚本本身。该脚本旨在 check/modify 一些 data/fields 集合,例如可以表示为哈希表。逻辑很简单——检查一些值并根据之前的检查修改其他值。逻辑很简单但应该很灵活,我有 "legacy" C 程序使用 lua。我首先找到 luaj,但后来我发现现代 Java 开箱即用地支持 ECMAScript,这就是我尝试使用 Nashorn 的原因。然后我发现Nashorn与jvm的集成过多,这可能会导致滥用。因此,我试图防止滥用禁用某些功能。首先,我发现了一些命令行参数,它们阻止了脚本中的某些扩展和 java 类 可用性。我还发现,Nashorn 公开了一些可能存在危险的函数,例如 quit()、load() 等。所以,我的代码看起来像这样:

ScriptEngine engine=new NashornScriptEngineFactory().getScriptEngine(new String[]{"-nj", "-nse"}, null
        new ClassFilter()
        {
            @Override
            public boolean exposeToScripts(String s)
            {
                return false;
            }
        });
Bindings bd;
bd=engine.getBindings(ScriptContext.ENGINE_SCOPE);
bd.remove("loadWithNewGlobal");
bd.remove("load");
bd.remove("quit");
// ... and so on

据我了解,由于 "bd" 是引用,它会删除实际绑定,并且无法从脚本内部调用这些函数。但是后来我试着列出所有绑定,发现有none!甚至在删除之前,我看到 bd 的大小为“0”并且绑定映射为空:

System.out.printf("Bindings no: %d\n", bd.size());    
for(String key : bd.keySet())
{
    System.out.printf("'%s'='%s'\n", key, bd.get(key).toString());
}

打印“0”,仅此而已。

所以,我其实有两个问题: 1) 为什么我看不到所有绑定? (虽然我可以删除它们并且我看到如果不删除这些函数可以从脚本中调用,但是在我删除它们之后它们不再可用并且每次调用都会抛出异常) 我怎样才能列出绑定的内容呢? 2)还有什么我忘记的,应该在脚本中禁用吗? (当然,除了无限循环等等 - 用户或多或少 "trusted",但我还是想阻止某些 "dangerous" 操作)

谢谢

第一部分:

如果您在全局范围内评估以下内容,您将获得所有属性,包括不可枚举的属性。

Object.getOwnPropertyNames(this)

另请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames

(根据 "BblKTOP" 的评论更新)

使用 javax.script.Bindings 迭代键集时,仅返回 (JS) 可枚举属性。但是相当于 Object.getOwnPropertyNames(this)。那将是这样的:

import javax.script.*;
import jdk.nashorn.api.scripting.*;

public class Main {
   public static void main(String[] args) throws Exception {
      ScriptEngineManager m = new ScriptEngineManager();
      ScriptEngine e = m.getEngineByName("nashorn");
      ScriptObjectMirror thiz = (ScriptObjectMirror)e.eval("this");
      // ScriptObjectMirror.getOwnKeys(boolean) returns all own property names. 
      // "true" to return all non-enumerable property names as well.
      // This is equivalent to JS call:
      //     Object.getOwnPropertyNames(this)
      for (String key : thiz.getOwnKeys(true)) {
          System.out.println(key);
      }
   }
}

第二部分:

我想你似乎已经涵盖了。但是您可能需要确保 运行 启用了安全管理器。设置安全管理器后,所有 "eval"-ed 脚本都被视为沙箱脚本,因此不允许进行任何安全敏感操作。

沙盒的另一种选择:考虑一种您可以翻译成的领域特定语言JavaScript。

通过 ScriptObjectMirror#getOwnKeys 发现 Nashorn returns 有效属性。以下代码打印有效绑定:

    bd=engine.getBindings(ScriptContext.ENGINE_SCOPE);
    for(String key : ((ScriptObjectMirror) bd).getOwnKeys(true))
    {
        if(key!=null)
        {
            System.out.printf("'%s'='%s'\n", key, bd.get(key));
        }
    }