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

Rak*_*yal 21 java security

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

将类加载到JVM后,将不会再次加载同一个类(我重复,同一个类)

引自oreilly].但是之后的事情,为什么在运行这个类我得到
java.lang.SecurityException:禁止的包名:java

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

Chr*_*ung 25

永远不允许用户代码将类放入标准Java包之一.这样,用户代码就无法访问Java实现中的任何包私有类/方法/字段.其中一些包私有对象允许访问JVM内部.(我正在考虑SharedSecrets.)

  • 原则上我同意对所带来的风险的分析,但请注意,如果您的类位于具有相同名称的包中并且由相同的ClassLoader加载,则您只能访问包私有内容. (3认同)
  • 不,这不是原因.用户代码*可以通过Reflection API访问`java`类中的私有成员.那个`javax`包下的代码怎么样?JVM确实允许在那里定义新类. (2认同)

Sam*_*ivu 16

首先,这些类型的限制适用于强制Java沙箱.也就是说,在受信任的环境中运行不受信任的代码.例如,在您的浏览器中的计算机(可信环境)上运行某个站点(您不一定信任)的applet.目的是禁止不受信任的代码访问包私有的东西,这可以帮助它逃离沙箱.

通常,这些限制由SecurityManager强制执行,因此当您在命令行上运行自己的应用程序时,不应该发生这些限制(除非您明确指定使用SecurityManager).当你控制环境时,你可以去编辑Java的rt.jar中的String.class定义(从技术上讲,你可以不确定许可证说的是什么).正如我所说,限制通常在SecurityManager中,但是关于java.*包的这个特殊规则是在ClassLoader类中.

回答你的问题:我的猜测是java.*检查是因为a)历史原因b)在Java核心的某个地方检查类的名称,例如:所有以java开头的类.*get特别待遇.

但是,请考虑即使您设法创建了一个名为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方法来绕过此限制.

顺便说一句:核心java.lang.String保证在代码执行之前加载,因为它在任何地方都被引用,你不会先用你的用户代码到达那里.在尝试加载类之前,JVM设置到一定程度,更不用说执行它了.

  • 这是最好的答案,但还有更多.通过"Java代理"使用`java.lang.instrument` API,可以*重新定义任何类加载器加载的任何类,包括由引导类加载器定义的`java.lang.String`类. . (2认同)

Jon*_*eld 9

你不能拥有"java.*"包名.这实际上是在Java核心中进行了硬编码,因此您甚至无法授予安全管理员权限来解决它(参见ClassLoader :: preDefineClass(...))


Viv*_*sse 7

java是保留的包名称.只有JVM中的类可以驻留在此包中.

如果任何人都可以在Java包中编写,那么可能会导致库通过自己的实现任意替换核心Java类.从破解核心Java功能到执行恶意代码,这可能会产生很多想法.