为什么`java.lang.SecurityException:禁止包名:java`是必需的?

时间:2010-09-27 13:50:32

标签: java security

我创建了一个类“String”并将其放在包“java”中[实际上我想创建 java.lang 以查看classLoader加载哪个类

  

一旦将类加载到JVM中,就可以了   同一课(我重复,同一课)   将不会再次加载

引自oreilly]。但那件事后来,为什么在这个班级上我得到了 java.lang.SecurityException:禁止的包名: java

为什么安全性原因java不允许我在 java 包中有一个类?如果没有这样的检查,可以做什么?

8 个答案:

答案 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,因此它不能被子类覆盖。

privatepreDefineClass的{​​{1}}方法调用。这意味着defineClass可供子类访问,他们可以调用它,但是他们将无法更改其实现。