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

Больше я узнал о питании java.lang.reflect.AccessibleObject.setAccessible, более удивленный, который я в том, что это может сделать. Это адаптировано от моего ответа до вопроса (Используя отражение для изменения статического заключительного 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?
    • Мог Java был разработан относительно НЕ, имеют эту потребность во-первых?
    • Что было бы негативные последствия (если таковые имеются) такого дизайна быть?
  • Можно ли ограничить setAccessible к законному использованию только?
    • Это только через SecurityManager?
      • Как это работает? Белый список/черный список, гранулярность, и т.д.?
      • Действительно ли распространено должным быть настроить его в Ваших приложениях?
    • Я могу записать свои классы, чтобы быть setAccessible- доказательство независимо от SecurityManager конфигурация?
      • Или во власти я того, кто бы ни управляет конфигурацией?

Я предполагаю, что еще один важный вопрос: Я ДОЛЖЕН ВОЛНОВАТЬСЯ ОБ ЭТОМ???

Ни один из моих классов не имеет подобия осуществимой конфиденциальности вообще. Шаблон "одиночка" (помещающий сомнения относительно его достоинств в стороне) теперь невозможно осуществить. Как мои отрывки выше шоу, даже некоторые основные предположения того, как 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!"
   }
}

Действительно ли я - единственный, кто думает, что это - ОГРОМНОЕ беспокойство?

97
задан Yvette Colomb 12 November 2018 в 15:00
поделиться

3 ответа

Нужно ли мне об этом беспокоиться????

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

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

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

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

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

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

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

"Модификаторы доступа Java не предназначены для того, чтобы быть механизмом безопасности."

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

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

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

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

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

Могла ли Java быть спроектирована так, чтобы не иметь такой необходимости в первую очередь?

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

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

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

Могу ли я написать классы, чтобы они были защищены от setAccessible независимо от конфигурации SecurityManager? ... Или я нахожусь во власти того, кто управляет конфигурацией?

Вы не можете, и вы, несомненно, можете.

103
ответ дан 24 November 2019 в 05:28
поделиться
  • Каковы действительно законные способы использования setAccessible ?

Модульное тестирование, внутреннее устройство JVM (например, реализация System.setError (...) ) и так далее.

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

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

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

Да.

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

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

  • Часто ли приходится настраивать его в ваших приложениях?

Нет.

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

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

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

В ответ на продолжение

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

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

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

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

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

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

15
ответ дан 24 November 2019 в 05:28
поделиться

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

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

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

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

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

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

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

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

См. этот ответ про final class для хорошего объяснения. Смотрите также блог от Sami Koivu для более подробного изучения безопасности java.

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

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

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

11
ответ дан 24 November 2019 в 05:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: