java - 如何对 Eclipse 项目使用非 URLClassLoader 类加载器,或者以其他方式检测我正在 Eclipse 中运行?

标签 java eclipse classloader rhino

我正在 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);

Eclipse(已损坏)

我最近已经达到了可以在框架上运行脚本的地步,并开始从我的朴素安全管理器那里收到以下消息:

Blocked file read: [project]\target\classes\org\mozilla\javascript\WrapFactory.class

与一堆特定于 Rhino 的类相关。

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

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

作为 Jar 的 Maven(可以工作但不理想)

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

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

我考虑过的解决方案是:

  • 检测是否在 Eclipse 中运行,并禁用安全管理器。这似乎是一种不好的做法,需要通过 git 进行传输的配置,因为我们已经 .project gitignored,正如我在另一篇文章中读到的:

    Actually the code is not being run inside Eclipse, but in a separate Java process started by Eclipse, and there is per default nothing being done by Eclipse to make it any different than any other invocation of your program.

    这对我来说非常奇怪,因为独立执行已编译的 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

最佳答案

我设法通过更新安全管理器以允许在类路径的 net.myapp.scripting 的子目录中打开 .class 文件来解决这个问题,这是需要脚本的地方类被存储。我还通过运行一个简短的脚本来“热身”Rhino,该脚本将加载我需要的任何 Rhino 类(包括数组)。

java.util 类工作得很好,来自 rt.jar

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

关于java - 如何对 Eclipse 项目使用非 URLClassLoader 类加载器,或者以其他方式检测我正在 Eclipse 中运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21937819/

相关文章:

java - 是否可以将一个 Json 对象中的图像和字符串返回给客户端

java - 我应该忽略 GUI 类的自动代码审查错误吗?

JavaFX 类中不使用线程

java - 区分消息对话框中 no, close 选项的行为

java - ClassLoader问题导致ClassCastException的解决方法

java - 从单独的 JFrame 获取数据

eclipse - 如何从 Eclipse 安装中删除 m2eclipse?

eclipse - 可以说服 Eclipse 在 C++ 中换行注释吗?

java - 用于 Hibernate 映射的自定义类加载器

java - 从 WAR 文件获取文件