我创建了一个类“String”并将其放在包“java”中[实际上我想创建 java.lang 以查看classLoader加载哪个类
一旦将类加载到JVM中,就可以了 同一课(我重复,同一课) 将不会再次加载
为什么安全性原因java不允许我在 java 包中有一个类?如果没有这样的检查,可以做什么?
答案 0 :(得分:24)
用户代码永远不会允许将类放入其中一个标准Java包中。这样,用户代码就无法访问Java实现中的任何包私有类/方法/字段。其中一些包私有对象允许访问JVM内部。 (我特别想到SharedSecrets
。)
答案 1 :(得分:16)
首先,这些类型的限制适用于强制Java沙箱。也就是说,在受信任的环境中运行不受信任的代码。例如,在您的浏览器中的计算机(可信环境)上运行某个站点(您不一定信任)的applet。目的是禁止不受信任的代码访问包私有的东西,这可能有助于它逃离沙箱。
通常这些限制是由SecurityManager强制执行的,因此当您在命令行上运行自己的应用程序时,不应该发生这些限制(除非您明确指定使用SecurityManager)。当你控制环境时,你可以去编辑Java的rt.jar中的String.class定义(从技术上讲,你可以不确定许可证说的是什么)。正如我所说,限制通常在SecurityManager中,但是关于java。*包的这个特殊规则是在ClassLoader类中。
回答你的问题:我的猜测是java。*检查是因为 a)历史原因 b)在Java核心的某个地方,检查类的名称,例如:所有以java开头的类。*得到特殊处理。
但是,请注意,即使您设法创建了一个名为java.lang.String的类,它也不会与Java核心定义的java.lang.String类相同。它只是一个具有完全相同名称的类。类标识不仅仅是类的名称,即使你真的很难理解,除非你真的使用ClassLoader。
因此,java.lang包中的应用程序类加载器加载的类将无法访问核心java.lang包私有内容。
为了说明这一点,尝试使用main方法创建一个名为javax.swing.JButton的类并执行它。你会得到一个java.lang.NoSuchMethodError: main
。那是因为java在你的类之前找到了“真正的”JButton,而真正的JButton没有一个main方法。
在Java独立应用程序中,您可以通过使用reflection和setAccessible直接调用其中一个私有本机defineClassx方法来解决此限制。
BTW:核心java.lang.String保证在代码执行之前加载,因为它在任何地方都被引用,你不会先用你的用户代码到达那里。即使尝试加载类,JVM也会设置到一定程度,更不用说执行它了。
答案 2 :(得分:8)
您不能拥有“java。*”包名称。这实际上是在Java核心中进行了硬编码,因此您甚至无法授予安全管理员权限来解决它(参见ClassLoader :: preDefineClass(...))
答案 3 :(得分:7)
java
是保留的包名称。只有JVM中的类可以驻留在此包中。
如果有人可以在Java包中编写,那么可能会导致库通过自己的实现任意替换核心Java类。从破解核心Java功能到执行恶意代码,这可能会产生很多想法。
答案 4 :(得分:2)
如果程序可以使用木马版本覆盖JVM核心类,则程序可以绕过安全措施。例如,String几乎无处不在。
答案 5 :(得分:1)
来自ClassLoader.defineClass(..)
javadoc:
...指定的类名不能以"开头。 java的。 ",因为"中的所有课程java。*包只能由bootstrap类加载器
定义
和
抛出:... SecurityException - 如果尝试将此类添加到包含由不同于该类的证书集签名的类的包,或者类名以&#34开头; java的。 "
答案 6 :(得分:0)
可能在重构/补丁应用/等。你已经添加到包名称' java',它通常是一个包含包的文件夹。
所以你可以用结构结束: SRC-> main-> Java的> java.com.yourpackage.name
它也可能发生在测试中: SRC-> main->测试 - > Java的> java.com.yourpackage.name
在IDE中验证并删除" java。"部分
答案 7 :(得分:0)
从java.lang.ClassLoader
的{{1}}方法摘录:
preDefineClass
请注意,/* Determine protection domain, and check that:
- not define java.* class,
- signer of this class matches signers for the rest of the classes in
package.
*/
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
...
// Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
name.substring(0, name.lastIndexOf('.')));
}
...
}
是抽象类,这意味着子类(例如java.lang.ClassLoader
)将实际实现它。但是,SecureClassLoader
方法是preDefineClass
,因此它不能被子类覆盖。
private
由preDefineClass
的{{1}}方法调用。这意味着defineClass
可供子类访问,他们可以调用它,但是他们将无法更改其实现。