почему `java.lang.SecurityException: Запрещенное имя пакета: требуется java`? - PullRequest
21 голосов
/ 27 сентября 2010

Я создал класс «String» и поместил его в пакет «java» [на самом деле я хотел создать java.lang , чтобы увидеть, какой класс загружается classLoader как

Как только класс загружен в JVM, тот же класс (повторяю, тот же класс) не будет загружен снова

, цитируемый от oreilly].Но позже, почему при запуске этого класса я получаю
java.lang.SecurityException: Запрещенное имя пакета: java

По какой причине безопасности ява не позволяет мне иметькласс в java пакете?Что можно сделать, если такой проверки не будет?

Ответы [ 8 ]

24 голосов
/ 27 сентября 2010

Код пользователя никогда разрешено помещать классы в один из стандартных пакетов Java.Таким образом, пользовательский код не может получить доступ к каким-либо закрытым пакетам классам / методам / полям в реализации Java.Некоторые из этих закрытых для пакета объектов предоставляют доступ к внутренним компонентам JVM.(Я имею в виду SharedSecrets в частности.)

16 голосов
/ 27 сентября 2010

Во-первых, существуют ограничения такого типа для принудительного применения песочницы Java.То есть запуск ненадежного кода в доверенной среде.Например, запуск апплета с какого-либо сайта (которому вы не обязательно доверяете) на вашем компьютере (в доверенной среде) в вашем браузере.Намерение состоит в том, чтобы запретить недоверенному коду получать доступ к частным данным пакета, которые могли бы помочь ему избежать «песочницы».

Обычно эти ограничения применяются SecurityManager, поэтому они не должны возникать, когда вы запускаете свое собственное приложение.в командной строке (если вы явно не укажете использовать SecurityManager).Когда вы управляете средой, вы можете просто перейти и отредактировать определение String.class внутри rt.jar вашего Java (и вы можете, во всяком случае, технически не знать, что говорит лицензирование).Как я уже сказал, ограничения обычно в SecurityManager, но это конкретное правило о пакетах java. * Находится в классе ClassLoader.

Чтобы ответить на ваш вопрос: я предполагаю, что проверка java. * Существует из-за) исторические причины б) где-то в ядре Java есть проверка имени класса, что-то вроде: все классы, начинающиеся с java. * получают специальную обработку.

Однако учтите, что даже если вам удалосьсоздайте класс с именем java.lang.String, это не будет тот же класс, что и java.lang.String, определенный ядром Java.Это был бы просто класс с точно таким же именем.Идентификация класса - это больше, чем просто имя класса, хотя это может быть сложно воспринимать, если вы действительно не играете с ClassLoaders.

Так что класс, загруженный загрузчиком классов приложения в пакете java.lang, не будетиметь доступ к основному пакету java.lang.

Чтобы проиллюстрировать это, попробуйте создать класс с именем javax.swing.JButton с помощью метода main и выполнить его.Вы получите java.lang.NoSuchMethodError: main.Это потому, что java находит «настоящий» JButton перед вашим классом, а настоящий JButton не имеет основного метода.

В автономном приложении Java вы можете обойти это ограничение, вызвав один изчастные нативные методы defineClassx напрямую с использованием отражений и setAccessible.

Кстати: ядро ​​java.lang.String гарантированно будет загружено до того, как ваш код когда-либо выполнится, потому что на него ссылаются везде, вы не получите его первым с помощьюкод пользователя.JVM настроен до такой степени, что даже не пытался загрузить ваш класс, не говоря уже о его выполнении.

8 голосов
/ 21 ноября 2011

У вас не может быть имен пакетов "java. *". На самом деле это жестко запрограммировано в ядре Java, поэтому вы даже не можете разрешить администратору безопасности работать с ним (см. ClassLoader :: preDefineClass (...))

7 голосов
/ 27 сентября 2010

java является зарезервированным именем пакета. В этом пакете могут находиться только классы внутри JVM.

Если кто-то может написать в пакете Java, это может привести к тому, что библиотеки произвольно заменят основные классы Java их собственными реализациями. Это может привести к размышлениям, от взлома основных функций Java до выполнения вредоносного кода.

2 голосов
/ 27 сентября 2010

Программа может обойти меры безопасности, если она может переопределить базовые классы JVM с помощью троянских версий.Например, String используется практически везде.

1 голос
/ 13 марта 2016

Из ClassLoader.defineClass(..) Javadoc:

... Указанное имя класса не может начинаться с «java.», Поскольку все классы в пакетах «java. *» Могут быть определены только загрузчиком классов начальной загрузки

и

Броски: ... SecurityException - Если сделана попытка добавить этот класс в пакет, который содержит классы, которые были подписаны набором сертификатов, отличным от этого класса, или если имя класса начинается с "java.".

0 голосов
/ 13 ноября 2018

выдержка из java.lang.ClassLoader 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 вызывается методом defineClass, который protected final. Это означает, что defineClass доступен для подклассов, и они могут вызывать его, но они не смогут изменить его реализацию.

0 голосов
/ 26 июня 2014

Вероятно, во время рефакторинга / применения патча / и т.д. Вы добавили в имя пакета слово «java», которое обычно является папкой, содержащей пакеты.

Итак, вы можете закончить со структурой: src-> Main-> Java-> java.com.yourpackage.name

Это может также произойти для теста: src-> Main-> тест-> Java-> java.com.yourpackage.name

Проверьте это в вашей IDE и удалите "Java". часть

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...