Как ограничить setAccessible только «законным» использованием?

Чем больше я узнал о силе java.lang.reflect.AccessibleObject.setAccessible , тем больше я удивляюсь тому, что он может сделать. Это адаптировано из моего ответа на вопрос ( используя reflection для изменения статического окончательного файла File.separatorChar для модульного тестирования ).

 import java.lang.reflect.*; public class EverythingIsTrue { static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } public static void main(String args[]) throws Exception { setFinalStatic(Boolean.class.getField("FALSE"), true); System.out.format("Everything is %s", false); // "Everything is true" } } 

Вы можете делать поистине возмутительные вещи:

 public class UltimateAnswerToEverything { static Integer[] ultimateAnswer() { Integer[] ret = new Integer[256]; java.util.Arrays.fill(ret, 42); return ret; } public static void main(String args[]) throws Exception { EverythingIsTrue.setFinalStatic( Class.forName("java.lang.Integer$IntegerCache") .getDeclaredField("cache"), ultimateAnswer() ); System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42" } } 

Предположительно, разработчики API понимают, насколько неприхотливым может быть setAccessible , но он должен признать, что он имеет законные цели для его предоставления. Поэтому мои вопросы:

  • Каковы действительно законные setAccessible использования setAccessible ?
    • Может ли Java быть спроектирована так, чтобы НЕ иметь эту потребность в первую очередь?
    • Каковы были бы негативные последствия (если таковые имеются) такого дизайна?
  • Можете ли вы ограничить setAccessible только законным использованием?
    • Это только через SecurityManager ?
      • Как это работает? Белый список / черный список, гранулярность и т. Д.?
      • Обычно ли приходится настраивать его в своих приложениях?
    • Могу ли я писать свои classы, чтобы быть установленными? Уверенно-защищенными независимо от конфигурации SecurityManager ?
      • Или я во власти того, кто управляет конфигурацией?

Я предполагаю, что еще один важный вопрос: мне нужно заняться этим?

Ни один из моих classов не имеет какого-либо подобия принудительной конфиденциальности, что-то никогда. Шаблон одноэлементности (ставящий под сомнение его достоинства) теперь невозможно обеспечить соблюдение. Как показывают мои fragmentы, даже некоторые базовые предположения о том, как основаны на Java, даже не гарантированы.

ЭТИ ПРОБЛЕМЫ НЕ РЕАЛЬНЫ ???


Хорошо, я только что подтвердил: благодаря setAccessible строки Java НЕ являются неизменными.

 import java.lang.reflect.*; public class MutableStrings { static void mutate(String s) throws Exception { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); value.set(s, s.toUpperCase().toCharArray()); } public static void main(String args[]) throws Exception { final String s = "Hello world!"; System.out.println(s); // "Hello world!" mutate(s); System.out.println(s); // "HELLO WORLD!" } } 

Я единственный, кто думает, что это ОГРОМНАЯ забота?

Мне НУЖНО СМОТРЕТЬ ЭТО?

Это полностью зависит от того, какие типы программ вы пишете и для какой архитектуры.

Если вы распространяете программный компонент, называемый foo.jar, людям в мире, вы все равно в их власти. Они могут изменять определения classов внутри вашего .jar (посредством обратного проектирования или прямого управления байт-кодом). Они могут запускать ваш код в их собственной JVM и т. Д. В этом случае беспокойство не принесет вам никакой пользы.

Если вы пишете веб-приложение, которое взаимодействует только с людьми и системами через HTTP, и вы управляете сервером приложений, это также не вызывает беспокойства. Конечно, коллеги-кодеры в вашей компании могут создавать код, который разбивает ваш шаблон singleton, но только если он действительно этого захочет.

Если ваша будущая работа заключается в написании кода в Sun Microsystems / Oracle, и вам поручено писать код для ядра Java или других доверенных компонентов, это то, о чем вы должны знать. Однако беспокойство просто заставит вас потерять ваши волосы. В любом случае они, вероятно, заставят вас ознакомиться с Правилами безопасного кодирования вместе с внутренней документацией.

Если вы собираетесь писать Java-апплеты, инфраструктура безопасности – это то, о чем вы должны знать. Вы обнаружите, что неподписанные апплеты, пытающиеся вызвать setAccessible, просто приведут к исключению SecurityException.

setAccessible – это не единственное, что происходит вокруг обычных проверок целостности. Существует не-API, базовый Java-class под названием sun.misc.Unsafe, который может делать практически все, что он хочет, включая прямой доступ к памяти. Родительский код (JNI) может обойти этот тип контроля.

В изолированной среде (например, Java-апплеты, JavaFX) каждый class имеет набор разрешений и доступ к Unsafe, setAccessible и определение собственных реализаций контролируется SecurityManager.

«Модификаторы доступа Java не предназначены для обеспечения безопасности».

Это очень зависит от того, где выполняется Java-код. Основные classы Java используют модификаторы доступа в качестве механизма безопасности для принудительного использования песочницы.

Каковы действительно законные цели использования setAccessible?

Основные classы Java используют его как простой способ доступа к материалам, которые должны оставаться конфиденциальными по соображениям безопасности. В качестве примера, среда Java Serialization использует ее для вызова частных конструкторов объектов при десериализации объектов. Кто-то упомянул System.setErr, и это будет хороший пример, но любопытно, что методы classа System setOut / setErr / setIn используют собственный код для установки значения конечного поля.

Другим очевидным законным использованием являются frameworks (настойчивость, веб-фреймворки, инъекции), которые необходимо заглянуть во внутренние объекты.

Отладчики, на мой взгляд, не попадают в эту категорию, поскольку они обычно не работают в одном JVM-процессе, а вместо этого интерфейс с JVM использует другие средства (JPDA).

Может ли Java быть спроектирована так, чтобы НЕ иметь эту потребность в первую очередь?

Это довольно глубокий вопрос, чтобы хорошо ответить. Я думаю, да, но вам нужно будет добавить еще какой-то другой механизм (ы), который может быть не самым лучшим.

Можете ли вы ограничить setAccessible только законным использованием?

Самое прямое ограничение OOTB, которое вы можете применить, – это иметь SecurityManager и разрешать setAccessible только для кода, поступающего из определенных источников. Это то, что уже делает Java – стандартные classы Java, которые поступают из вашего JAVA_HOME, разрешены для выполнения setAccessible, в то время как неподписанные classы апплетов из foo.com не разрешают делать setAccessible. Как уже было сказано, это разрешение двоично, в том смысле, что оно есть или нет. Нет очевидного способа разрешить setAccessible изменять некоторые поля / методы, не разрешая другим. Однако, используя SecurityManager, вы можете запретить classы полностью ссылаться на определенные пакеты с reflectionм или без него.

Могу ли я писать свои classы, чтобы они были установлены с возможностью доступа, независимо от конфигурации SecurityManager? … Или я во власти того, кто управляет конфигурацией?

Вы не можете, и вы наверняка.

  • Каковы действительно законные setAccessible использования setAccessible ?

Единичное тестирование, внутренности JVM (например, внедрение System.setError(...) ) и т. Д.

  • Может ли Java быть спроектирована так, чтобы НЕ иметь эту потребность в первую очередь?
  • Каковы были бы негативные последствия (если таковые имеются) такого дизайна?

Множество вещей было бы невыполнимым. Например, различные настойчивости Java, сериализации и зависимостей зависят от рефлексии. И почти все, что полагается на соглашения JavaBeans во время выполнения.

  • Можете ли вы ограничить setAccessible только законным использованием?
  • Это только через SecurityManager ?

Да.

  • Как это работает? Белый список / черный список, гранулярность и т. Д.?

Это зависит от разрешения, но я считаю, что разрешение на использование setAccessible является двоичным. Если вы хотите детализации, вам нужно либо использовать другой загрузчик classов с другим менеджером безопасности для classов, которые вы хотите ограничить. Я предполагаю, что вы можете реализовать собственный менеджер безопасности, который реализует более тонкую логику.

  • Обычно ли приходится настраивать его в своих приложениях?

Нет.

  • Могу ли я писать свои classы, чтобы быть установленными? Уверенно-защищенными независимо от конфигурации SecurityManager ?
    • Или я во власти того, кто управляет конфигурацией?

Нет, вы не можете, и да, вы.

Другой альтернативой является «принудительное выполнение» этого путем использования инструментов анализа исходного кода; например, пользовательские pmd или findbugs . Или выборочный обзор кода кода, идентифицированного (скажем) grep setAccessible ...

В ответ на

Ни один из моих classов не имеет какого-либо подобия принудительной конфиденциальности, что-то никогда. Шаблон одноэлементности (ставящий под сомнение его достоинства) теперь невозможно обеспечить соблюдение.

Если это вас беспокоит, я полагаю, вам нужно волноваться. Но на самом деле вы не должны пытаться заставить других программистов уважать ваши дизайнерские решения. Если они достаточно глупы, чтобы безвозмездно создать несколько экземпляров ваших синглтонов (например), они могут жить с последствиями.

И если вы имеете в виду «конфиденциальность», чтобы охватить смысл защиты конфиденциальной информации от раскрытия, вы также лаяете неправильное дерево. Способ защиты конфиденциальных данных заключается в том, чтобы не допустить ненадежного кода в изолированную программную среду безопасности, которая имеет дело с конфиденциальными данными. Модификаторы Java-доступа не предназначены для обеспечения безопасности.

<Пример строки> – Я единственный, кто считает, что это ОГРОМНАЯ забота?

Наверное, не единственный :-). Но ИМО, это не проблема. Принято, что ненадежный код должен выполняться в изолированной программной среде. Если у вас есть доверенный код / ​​доверенный программист, который делает такие вещи, то ваши проблемы хуже, чем неожиданно изменяемые строки. (Думайте логические бомбы …)

Отражение действительно является ортогональным безопасности / безопасности в этой перспективе.

Как мы можем ограничить reflection?

Java имеет менеджер безопасности и ClassLoader качестве основы для своей модели безопасности. В вашем случае, я думаю, вам нужно посмотреть на java.lang.reflect.ReflectPermission .

Но это не полностью решает проблему рефлексии. Доступные отражающие возможности должны обладать мелкозернистой схемой авторизации, которая сейчас не имеет места. Например, чтобы позволить определенной структуре использовать reflection (например, Hibernate), но не остальная часть вашего кода. Или позволить программе отражать только в режиме «только для чтения», для целей отладки.

Одним из подходов, который может стать мейнстримом в будущем, является использование так называемых зеркал для разделения отражающих возможностей от classов. См. « Зеркала: принципы проектирования для объектов уровня мета-уровня» . Однако есть и другие исследования, которые решают эту проблему. Но я согласен, что проблема более жесткая для динамического языка, чем статические языки.

Должны ли мы беспокоиться о сверхдержаве, которую дает нам reflection? Да и нет.

Да, в том смысле, что платформа Java должна быть обеспечена с помощью Classloader и менеджера безопасности. Способность возиться с reflectionм может рассматриваться как нарушение.

Нет в том смысле, что большинство систем в любом случае не полностью безопасны. Многие classы часто могут быть подclassифицированы, и вы могли бы уже злоупотреблять системой именно этим. Конечно, classы можно сделать final или запечатать, чтобы их нельзя было подclassифицировать в другой банке. Но только несколько classов обеспечены правильно (например, String) в соответствии с этим.

См. Этот ответ о финальном classе для приятного объяснения. См. Также блог от Сами Койву для более хакинга хау по безопасности.

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

Важно также отметить, что безопасность в любом случае относительна . На уровне языка вы можете, например, не мешать модульной форме, потребляющей 100% процессора или потребляющей всю память до OutOfMemoryException . Такие проблемы необходимо решать другими способами. Возможно, мы увидим в будущем Java, расширенный с использованием квот использования ресурсов, но это не для завтра 🙂

Я мог бы больше рассказать об этом, но я думаю, что я сделал свою точку зрения.

  • Тестирование модhive с помощью Spring Security
  • В .NET 4.0, как мне «изолировать» сборку в памяти и выполнить метод?
  • Safari продолжает запрашивать разрешение на доступ к цепочке ключей
  • Как изменить заголовок заголовка Firefox для всех HTTP-запросов
  • MD5 hash с солью для хранения пароля в БД в C #
  • Как настроить ASP.NET Web API AuthorizeAttribute для необычных требований
  • Целостность системных файлов Windows 7
  • Должен ли я устанавливать обновления Internet Explorer, хотя я отключил его?
  • Как разблокировать файлы chm - кнопка разблокирования отсутствует
  • По умолчанию SecurityProtocol в .NET 4.5
  • Как настроить cookie HttpOnly в tomcat / java webapps?
  • Давайте будем гением компьютера.