启用安全管理器时 URLClassLoader 发出的 ClassNotFoundException
ClassNotFoundException issued by URLClassLoader when the Security Manager is enabled
对于一个实验项目,我正在尝试使用 URLClassLoader 加载 class 并启用安全管理器。尽管 URL 和 class 确实存在,但代码总是失败并出现 ClassNotFoundException。
至少在 java 的以下版本中观察到此行为(我的系统上可用的版本,MacOSX Mojave 10.14.6;尚未在 Windows 或 [=71 上测试=] 或其他 Java 实现):
java 版本“1.8.0_181”
Java(TM) SE 运行时环境(build 1.8.0_181-b13)
Java HotSpot(TM) 64 位服务器 VM(内部版本 25.181-b13,混合模式)
java 版本 "10.0.2" 2018-07-17
Java(TM) SE 运行时环境 18.3(内部版本 10.0.2+13)
Java HotSpot(TM) 64 位服务器 VM 18.3(内部版本 10.0.2+13,混合模式)
java 版本 "12.0.1" 2019-04-16
Java(TM) SE 运行时环境(build 12.0.1+12)
Java HotSpot(TM) 64 位服务器 VM(内部版本 12.0.1+12,混合模式,共享)
经过数小时的故障排除(检查路径、寻找路径中的不可见字符、阅读 class 加载程序上的文档等),我意识到 只有在启用安全管理器时才会发生异常。当我禁用它时,发现 class 没有问题。我本以为会出现某种安全异常,但不是 ClassNotFoundException。
显然,安全管理器的缺失严重限制了 class 加载程序的实用性(尤其是如果想要加载不受信任的、已签名的 classes 和 jars)。创建class加载器的权限显然是在安全策略中授予的。
下面的代码是重现问题所需的最少代码。
我对 Java 比较陌生。我可能正在做一些愚蠢的事情。以前有人观察过这种行为吗?是故意的吗?我错过了什么吗?
感谢您的帮助。
.
├── ClassLoaderTest.class
├── ClassLoaderTest.java
├── Makefile
├── security.policy
└── untrusted
├── Makefile
├── Untrusted.class
└── Untrusted.java
1 directory, 7 files
// ClassLoaderTest.java
import java.net.URLClassLoader;
import java.net.URL;
public class ClassLoaderTest {
public static void main(String[] args) throws Exception {
URL[] urls = new URL[1];
urls[0] = new URL("file:./untrusted/"); // untrusted/ could be anywhere; for the purpose of the test, it is in the working directory
URLClassLoader loader = new URLClassLoader(urls);
Class<?> cl = loader.loadClass("Untrusted"); // one tries to load: untrusted/Untrusted.class
cl.getConstructor().newInstance(); // or cl.getDeclaredConstructor().newInstance()
System.exit(0);
}
}
public class Untrusted {
public Untrusted() {
System.out.println("Instantiation of Untrusted");
}
public static void main(String args[]) {
Untrusted u = new Untrusted();
}
}
// security.policy
// permissions granted to any code (no matter where it came from or whether it is signed)
// THIS IS OBVIOUSLY FOR TESTING ONLY, only trusted sources should be granted a createClassLoader permission
grant {
permission java.lang.RuntimePermission "createClassLoader";
};
程序的结果如下:
没有安全管理器:有效
$ java ClassLoaderTest
Instantiation of Untrusted
启用安全管理器:失败!
$ java -Djava.security.manager -Djava.security.policy=security.policy ClassLoaderTest
Exception in thread "main" java.lang.ClassNotFoundException: Untrusted
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:436)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at ClassLoaderTest.main(ClassLoaderTest.java:10)
将问题提交给 Oracle 后,由于以下非常有用的标记(对于与安全管理器一起工作的人),他们解决了问题:
-Djava.security.debug=访问
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8229532
这样问题就清楚多了:
// ... more lines above (skipped for clarity)
access: access denied ("java.util.PropertyPermission" "user.dir" "read") // shows up only in debug mode
Exception in thread "main" java.lang.ClassNotFoundException: Untrusted
...
因此必须向 security.policy 文件添加权限:
grant {
permission java.lang.RuntimePermission "createClassLoader";
permission java.util.PropertyPermission "user.dir", "read"; // new line
};
它解决了问题。
因此,该问题被标记为不存在,并由 Oracle 的受让人关闭。虽然他的回复很有帮助,但我仍然认为存在错误,因为 SDK(而不是应用程序)抛出了错误的异常:ClassNotFoundException 而不是权限或安全异常。
对于不知道 -Djava.security.debug=access 属性 的人(以及生产环境中的用户或管理员),这可能会产生误导并且非常混乱。
无论如何,我的问题已经关闭,我希望这个解决方案对遇到类似问题的其他人有所帮助。
向大家致以最诚挚的问候。
对于一个实验项目,我正在尝试使用 URLClassLoader 加载 class 并启用安全管理器。尽管 URL 和 class 确实存在,但代码总是失败并出现 ClassNotFoundException。
至少在 java 的以下版本中观察到此行为(我的系统上可用的版本,MacOSX Mojave 10.14.6;尚未在 Windows 或 [=71 上测试=] 或其他 Java 实现):
java 版本“1.8.0_181” Java(TM) SE 运行时环境(build 1.8.0_181-b13) Java HotSpot(TM) 64 位服务器 VM(内部版本 25.181-b13,混合模式)
java 版本 "10.0.2" 2018-07-17 Java(TM) SE 运行时环境 18.3(内部版本 10.0.2+13) Java HotSpot(TM) 64 位服务器 VM 18.3(内部版本 10.0.2+13,混合模式)
java 版本 "12.0.1" 2019-04-16 Java(TM) SE 运行时环境(build 12.0.1+12) Java HotSpot(TM) 64 位服务器 VM(内部版本 12.0.1+12,混合模式,共享)
经过数小时的故障排除(检查路径、寻找路径中的不可见字符、阅读 class 加载程序上的文档等),我意识到 只有在启用安全管理器时才会发生异常。当我禁用它时,发现 class 没有问题。我本以为会出现某种安全异常,但不是 ClassNotFoundException。
显然,安全管理器的缺失严重限制了 class 加载程序的实用性(尤其是如果想要加载不受信任的、已签名的 classes 和 jars)。创建class加载器的权限显然是在安全策略中授予的。
下面的代码是重现问题所需的最少代码。
我对 Java 比较陌生。我可能正在做一些愚蠢的事情。以前有人观察过这种行为吗?是故意的吗?我错过了什么吗?
感谢您的帮助。
.
├── ClassLoaderTest.class
├── ClassLoaderTest.java
├── Makefile
├── security.policy
└── untrusted
├── Makefile
├── Untrusted.class
└── Untrusted.java
1 directory, 7 files
// ClassLoaderTest.java
import java.net.URLClassLoader;
import java.net.URL;
public class ClassLoaderTest {
public static void main(String[] args) throws Exception {
URL[] urls = new URL[1];
urls[0] = new URL("file:./untrusted/"); // untrusted/ could be anywhere; for the purpose of the test, it is in the working directory
URLClassLoader loader = new URLClassLoader(urls);
Class<?> cl = loader.loadClass("Untrusted"); // one tries to load: untrusted/Untrusted.class
cl.getConstructor().newInstance(); // or cl.getDeclaredConstructor().newInstance()
System.exit(0);
}
}
public class Untrusted {
public Untrusted() {
System.out.println("Instantiation of Untrusted");
}
public static void main(String args[]) {
Untrusted u = new Untrusted();
}
}
// security.policy
// permissions granted to any code (no matter where it came from or whether it is signed)
// THIS IS OBVIOUSLY FOR TESTING ONLY, only trusted sources should be granted a createClassLoader permission
grant {
permission java.lang.RuntimePermission "createClassLoader";
};
程序的结果如下:
没有安全管理器:有效
$ java ClassLoaderTest
Instantiation of Untrusted
启用安全管理器:失败!
$ java -Djava.security.manager -Djava.security.policy=security.policy ClassLoaderTest
Exception in thread "main" java.lang.ClassNotFoundException: Untrusted
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:436)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at ClassLoaderTest.main(ClassLoaderTest.java:10)
将问题提交给 Oracle 后,由于以下非常有用的标记(对于与安全管理器一起工作的人),他们解决了问题: -Djava.security.debug=访问
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8229532
这样问题就清楚多了:
// ... more lines above (skipped for clarity)
access: access denied ("java.util.PropertyPermission" "user.dir" "read") // shows up only in debug mode
Exception in thread "main" java.lang.ClassNotFoundException: Untrusted
...
因此必须向 security.policy 文件添加权限:
grant {
permission java.lang.RuntimePermission "createClassLoader";
permission java.util.PropertyPermission "user.dir", "read"; // new line
};
它解决了问题。
因此,该问题被标记为不存在,并由 Oracle 的受让人关闭。虽然他的回复很有帮助,但我仍然认为存在错误,因为 SDK(而不是应用程序)抛出了错误的异常:ClassNotFoundException 而不是权限或安全异常。
对于不知道 -Djava.security.debug=access 属性 的人(以及生产环境中的用户或管理员),这可能会产生误导并且非常混乱。
无论如何,我的问题已经关闭,我希望这个解决方案对遇到类似问题的其他人有所帮助。
向大家致以最诚挚的问候。