如何将CodeSource提供给我通过nashorn评估的脚本?

时间:2015-04-14 05:08:12

标签: java security nashorn

我遇到一个问题,在nashorn下运行的一些相当简单的代码正在查找系统属性。查找系统属性失败,显示AccessControlException

我的安全政策已经允许:

grant {
    permission java.util.PropertyPermission "*", "read, write";
};

在使用-Djava.security.debug=access,failure进行调试时,我发现CodeSource null对于有问题的ProtectionDomainjdk.nashorn.internal.runtime.Source

我将断点移到了构造函数中,经过几层间接后,我最终设法将问题跟踪到private Source(String name, String base, char[] content, URL url) { this.name = name; this.base = base; this.content = content; this.length = content.length; this.url = url; }

NashornScriptEngine

有一个null正在调用的公共构造函数,它最终将url设置为public Source(String name, char[] content) { this(name, baseName(name, (String)null), content, (URL)null); } public Source(String name, String content) { this(name, content.toCharArray()); } ,这是我看到代码通过的构造函数。

CodeSource

虽然我们确实将脚本作为字符串传递,但它是从HTML文件的代码块中提取的,所以理论上我可以为它提供public Source(String name, URL url, Charset cs) throws IOException { this(name, baseURL(url, (String)null), readFully(url, cs), url); } 。然后希望访问控制代码至少可以给它最低级别的信任,并且希望查找系统属性。

我看到传递URL的其他构造函数。 e.g:

ScriptEngine

对于我的生活,我无法弄清楚如何与ScriptEngine#eval进行互动,以鼓励nashorn引擎调用其中一个更好的构造函数。 String只有ReaderFILENAME的方法。有没有办法做到这一点?还有另一种方法可以确保在nashorn创建代码时正确设置CodeSource吗?

我知道它不是 - 在脚本上下文中设置{{1}}。这似乎完全被忽略了。

奇怪的是,我们也在JRuby下运行所有​​相同类型的测试,但我们在那里看不到同样的问题。所以无论发生什么,这对nashorn来说都是特别的。 (FWIW,我们从未在Rhino下看到过这种情况。)

3 个答案:

答案 0 :(得分:2)

提供CodeSource是一种安全功能。攻击者可以使用它来错误地声称JS代码来自特权位置,因此将其置于任何保护域中。 Nashorn只会将CodeSource与通过URL加载的代码相关联(因此可以确定它来自何处)。即使在Java中,将代码与其源关联也只允许类加载器执行,因此它受createClassLoader运行时权限的保护。 Its documentation甚至说:

  

“这是非常危险的许可。恶意   那么可以实例化自己的类加载器的应用程序   将自己的流氓类加载到系统中。这些新装   类可以放在任何保护域中   loader,从而自动授予类的权限   那个域。“

将“class”替换为“script”,您在此处也有同样的疑虑。 我可以看到Nashorn有一个同时使用CodeSourcechar[]的构造函数,但它必须对createClassLoader进行权限检查或者新的定制运行时权限

答案 1 :(得分:1)

您可以使用jdk.nashorn.api.scripting.URLReader(https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/URLReader.html)将URL包装为Reader。使用URLReader,nashorn将从该URL加载脚本并关联正确的CodeSource - 以便您对该URL的安全策略有效。

答案 2 :(得分:1)

文件:Main.java

import javax.script.*;

public class Main {
    public static void main(String[] ar) throws Exception {
        ScriptEngineManager m = new ScriptEngineManager();
        ScriptEngine e = m.getEngineByName("nashorn");
        System.out.println(e.eval("java.lang.System.getProperty('foo.bar')"));
    }
}

档案:foo.policy

grant {
    permission java.util.PropertyPermission "*", "read, write";
};

命令:

javac Main.java

java -Djava.security.manager -Dfoo.bar = sss -Djava.security.policy = foo.policy Main

“sss”按预期打印(使用jdk 1.8.0 update 40)