我正在Eclipse中研究一个Java项目,该项目使用Mozilla Rhino(而不是捆绑的JDK Rhino)执行可能不受信任的代码。为此,我建立了一个安全管理器,该管理器不允许文件访问或其他许多危险的操作。
该安全管理器在脚本本身执行之前一直可以执行任何操作,然后仅针对执行本身而锁定,并在执行以下操作后立即解锁:
Object lock = new Object();
MyAppCustomSecurityManager.instance.lock(lock, ThreadContext.CONTEXT_SCRIPT);
sc.exec(this.cx, this.globalScope);
MyAppCustomSecurityManager.instance.unlock(lock);
日蚀(破碎)
我最近到了可以在框架上运行脚本的地步,并且开始从我的本地安全管理器获取消息,内容如下:
读取的阻止文件:
[project]\target\classes\org\mozilla\javascript\WrapFactory.class
与一堆特定于Rhino的课程有关。
我的安全管理器中没有任何与创建或设置类加载器有关的与安全相关的日志条目。
项目类由
sun.misc.Launcher$AppClassLoader
加载。该类加载器也由ClassLoader.getSystemClassLoader()
和Thread.currentThread().getContextClassLoader()
返回。罐子里的Maven(工作但不理想)
当我在maven中运行此代码时,我首先使用
mvn package
和maven-shade-plugin
来获取“阴影” JAR。然后,我使用java -jar
执行该JAR,发现该问题不再存在,并且脚本已成功运行(但是安全地运行,因为任何打开文件的实际尝试都会被过滤)。我注意到调试语句报告的类加载器是相同的,这使我相信还有另一个类加载器,也许是尝试在Eclipse中运行它的一个URLClassLoader
,但是除了在stacktrace中我找不到它。在库代码的尴尬处,我真的无法向其中添加调试语句。显然,我可以在Maven中进行测试,但这并不理想,因为我失去了Eclipse的快速周转和调试器。
我考虑过的解决方案是:
检测是否在Eclipse中运行,并禁用安全管理器。这似乎是一个坏习惯,需要配置,因为我们已经忽略了
.project
git,并且确实在跨git进行传输,正如我在另一篇文章中所读到的:实际上,代码不是在Eclipse内部运行,而是在由Eclipse启动的单独Java进程中运行,并且默认情况下,Eclipse不会做任何事情来使其与程序的其他调用有所不同。
这对我来说非常奇怪,因为可以独立执行已编译的jar。
实际上,似乎
mvn exec:java
也已损坏,可能是因为未将类放入Jar中。允许打开类路径中的文件:
同样令人怀疑的是,由于人们可能会给包含
..
的名称并对其进行规范化将非常困难。类路径还可以包含我不希望脚本直接看到的内容,例如某些属性文件。让Eclipse通过外部工具调用我的jar
这需要相当长的两步构建过程,并且会降低生产率。
该应用程序设计为在Jar中运行,但是任何使非jar执行不安全的解决方案也存在风险,因为我不确定由于其他情况而导致任何用户可能需要运行它。应用程序在这样的jar外部运行时会遇到问题,这似乎也很奇怪。
我还通过运行打印到控制台的受信任脚本来尝试“预热” Rhino,但这只是将问题推迟到我的脚本试图加载应该加载的类之前。
堆栈跟踪如下:
Exception in thread "main" java.lang.NoClassDefFoundError: net/myapp/scripting/NodePosition
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2521)
at java.lang.Class.privateGetPublicMethods(Class.java:2641)
at java.lang.Class.getMethods(Class.java:1457)
at org.mozilla.javascript.JavaMembers.discoverAccessibleMethods(JavaMembers.java:380)
at org.mozilla.javascript.JavaMembers.discoverAccessibleMethods(JavaMembers.java:335)
at org.mozilla.javascript.JavaMembers.reflect(JavaMembers.java:450)
at org.mozilla.javascript.JavaMembers.<init>(JavaMembers.java:76)
at org.mozilla.javascript.JavaMembers.lookupClass(JavaMembers.java:838)
at org.mozilla.javascript.NativeJavaObject.initMembers(NativeJavaObject.java:90)
at org.mozilla.javascript.NativeJavaObject.<init>(NativeJavaObject.java:80)
at org.mozilla.javascript.NativeJavaObject.<init>(NativeJavaObject.java:70)
at org.mozilla.javascript.WrapFactory.wrapAsJavaObject(WrapFactory.java:149)
at org.mozilla.javascript.WrapFactory.wrap(WrapFactory.java:105)
at org.mozilla.javascript.ScriptRuntime.toObject(ScriptRuntime.java:962)
at org.mozilla.javascript.ScriptRuntime.toObjectOrNull(ScriptRuntime.java:918)
at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.java:2213)
at org.mozilla.javascript.gen.c2._c0(net.myapp.servercore.LocalFile@2ff95fc4:0)
at org.mozilla.javascript.gen.c2.call(net.myapp.servercore.LocalFile@2ff95fc4)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:398)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3065)
at org.mozilla.javascript.gen.c2.call(net.myapp.servercore.LocalFile@2ff95fc4)
at org.mozilla.javascript.gen.c2.exec(net.myapp.servercore.LocalFile@2ff95fc4)
at net.myapp.servercore.ScriptEnv.runScript(ScriptEnv.java:114)
at net.myapp.servercore.MyAppMain.<init>(MyAppMain.java:105)
at net.myapp.servercore.MyAppMain.main(MyAppMain.java:129)
Caused by: java.lang.ClassNotFoundException: net.myapp.scripting.NodePosition
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 26 more
最佳答案
我设法通过更新安全管理器以允许在类路径的.class
子目录中打开net.myapp.scripting
文件来解决此问题,在该目录中存储了脚本所需的类。我还通过运行一个简短的脚本来“预热” Rhino,该脚本将加载我需要的任何Rhino类(包括数组)。java.util
类工作得很好,来自rt.jar
。
但是,这似乎是容易出现安全问题的解决方法,因此,我将对看到任何更好的解决方案感兴趣。