如何对 Eclipse 项目使用非 URLClassLoader 类加载器,或者以其他方式检测我是否在 Eclipse



我正在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]targetclassesorgmozillajavascriptWrapFactory.class

与一堆犀牛特定的类有关。

我没有看到我的安全管理器中与创建或设置类加载器有关的任何与安全相关的日志条目。

项目类由sun.misc.Launcher$AppClassLoader加载。该类加载器也由ClassLoader.getSystemClassLoader()返回,Thread.currentThread().getContextClassLoader()

Maven as a Jar(工作但不理想)

当我在 maven 中运行它时,我首先使用mvn packagemaven-shade-plugin来获得一个"阴影"的 JAR。然后我使用java -jar执行该 JAR,发现问题不再存在并且脚本成功运行(但安全,因为任何打开文件的实际尝试都会被过滤)。我注意到调试语句报告的类加载器是相同的,这让我相信还有另一个类加载器,也许是一个URLClassLoader参与尝试在 Eclipse 中运行它,但我无法找到它,除非在库代码中一个尴尬位置的堆栈跟踪中,我无法真正添加调试语句。

显然,我可以在 Maven 中进行测试,但这并不理想,因为我失去了 Eclipse 的快速周转和调试器。

我考虑过的解决方案是:

  • 检测是否在 Eclipse 中运行,并禁用安全管理器。这似乎是一种不好的做法,需要像我们.projectgitignore 的那样跨 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出来。

但是,这似乎是一种容易出现安全问题的解决方法,因此我有兴趣看到更好的解决方案。

最新更新