Действительно ли приватные методы безопасны?

92

В Java privateмодификатор доступа считается безопасным, так как он не виден вне класса. Тогда и внешний мир не знает об этом методе.

Но я думал, что отражение в Java может нарушить это правило. Рассмотрим следующий случай:

public class ProtectedPrivacy{

  private String getInfo(){
     return "confidential"; 
  }

}  

Теперь из другого класса я собираюсь получить информацию:

public class BreakPrivacy{

   public static void main(String[] args) throws Exception {
       ProtectedPrivacy protectedPrivacy = new ProtectedPrivacy();
       Method method = protectedPrivacy.getClass().getDeclaredMethod("getInfo", null);
       method.setAccessible(true);
       Object result = method.invoke(protectedPrivacy);
       System.out.println(result.toString());
   }
} 

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

Но моя точка зрения стала недействительной, так как ниже строка кода.

Method method[] = new ProtectedPrivacy().getClass().getDeclaredMethods();

Теперь он method[]содержит все, что нужно сделать выше. Мой вопрос: есть ли способ избежать подобных вещей, используя отражение Java?

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

Советы по выбору уровня доступа:

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

Ручира Гаян Ранавира
источник
1
Использование обфускатора может помочь, поскольку getDeclaredMethodsвозвращает имена, которые выглядят как мусор.
Сергей Калиниченко
213
Частные, защищенные публичные и т. Д. Предназначены не для обеспечения безопасности, а для того, чтобы не допускать ошибок людей из лучших побуждений. Не используйте это в качестве меры безопасности
Ричард Тингл
20
В любом случае код Java можно декомпилировать. «Злоумышленник» может просто загрузить декомпилятор Java и прочитать ваш код или изменить «частный» на «открытый».
11684
7
Чтобы уточнить, что прокомментировал @RichardTingle (+1 кстати). Есть большая и важная разница между безопасностью и безопасностью. Если последнее - проблема смягчается с помощью модификаторов доступа; чтобы не сломать вещи случайно
пользователь
3
Все это довольно ясно программистам, где модификаторы доступа не существуют, как в Python. В этих языках частные / общедоступные просто различаются по соглашению в именах (в python все, что начинается с одного символа подчеркивания, следует считать частным). Это довольно ясно дает понять, что пометка чего-либо как «частное» не добавляет безопасности, но это всего лишь простой способ сказать, что люди должны использовать от вашего API. Я сомневаюсь, что проверка компилятора на эти вещи вообще поможет, поскольку следовать соглашению без «внешней» помощи чертовски легко.
Bakuriu

Ответы:

95

Это зависит от того, что вы подразумеваете под словом «безопасный». Если вы работаете с менеджером безопасности, который допускает подобные вещи, то да, вы можете делать с отражением всевозможные неприятные вещи. Но тогда в такой среде библиотеку, вероятно, можно просто изменить, чтобы сделать метод общедоступным.

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

Джон Скит
источник
3
Тангенциальный, я знаю, но не могли бы вы немного уточнить, каким в этом смысле был бы более строгий менеджер?
Грей
12
@Gray: экземпляр SecurityManager, который в check*основном выдает исключения для соответствующих вызовов.
Джон Скит
40

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

Вместе со знанием данных и методов вашего кода приходит ответственность знать, когда и как их использовать. Вы не ставите приватный в свой метод inIt, чтобы кто-то не узнал об этом, вы делаете это потому, что (а) они не узнают, что вы вызываете это только после foo и только если bar = 3.1415 и (b) потому что им нечего об этом знать.

Modifers доступа можно суммировать в простой фразе «TMI, чувак, я так не нужно знать , что».

Jmoreno
источник
3
Отличный ответ, но мне нужно было погуглить, чтобы узнать, что TMI означает слишком много информации. Думаю, мне нужно проводить больше времени в долине :-)
mikelong
7

Говоря «безопасно», вы защищаете себя или других разработчиков, которые используют ваш API, чтобы не навредить объекту, вызывая ваш частный метод. Но если вам или им действительно нужно вызвать этот метод, они могут сделать это с помощью Reflection.

Арсен Алексанян
источник
6

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

Любой фрагмент кода (написанный вами или другими), который пытается получить доступ к privateчлену вышеуказанного класса, по сути, роет себе могилу. privateчлены не являются частью общедоступного API и могут быть изменены без предварительного уведомления. Если клиент использует один из таких закрытых членов описанным выше способом, он сломается, если обновится до более новой версии API, в которой частный член был изменен.


источник
5

С легкостью приходит ответственность. Есть вещи, которые нельзя делать, и есть вещи, которые можно делать, но делать не следует .

Приватный модификатор предоставляется / используется наиболее ограниченным образом. Члены, которые не должны быть видимы вне класса, должны быть определены как частные. Но, как мы видим, это можно сломать с помощью Reflection. Но это не значит, что вы не должны использовать приватные - или они небезопасны. Речь идет о том, что вы должны использовать вещи разумно или конструктивно (например, размышления).

Рауль
источник
5

Предполагая, что вы доверяете клиентскому программисту своего API, другой способ взглянуть на то, насколько «безопасно» для них использовать эти конкретные функции.

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

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

robbie_c
источник
5

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

Как только вы выпустите свой код, люди смогут понять, как он работает. Невозможно «скрыть» логику, если вы хотите, чтобы код запускался на компьютере. Даже компиляция в двоичную форму - это просто уровень запутывания.

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

Manishearth
источник