Подтвердить что ты не робот

Является ли ключевое слово "final" Java действительно улучшающим безопасность?

Пока существует множество причин использовать ключевое слово final в Java, один из тех, что я продолжаю слышать снова и снова, заключается в том, что это делает ваш код более безопасным. Хотя это, похоже, имеет смысл в этом тривиальном случае:

public class Password
{
    public final String passwordHash;
    ...
}

С ключевым словом final вы можете ожидать, что никакой вредоносный код не сможет изменить переменную passwordHash. Однако с использованием отражения можно изменить последний модификатор в поле passwordHash.

Итак, "final" обеспечивает любую реальную безопасность, или это просто плацебо?

Edit: Есть очень интересная дискуссия, и я бы хотел принять более одного ответа. Спасибо всем за ваш вклад.

4b9b3361

Ответ 1

Это не "безопасность" в смысле "выдерживания атаки"; это больше похоже на "труднее испортить по ошибке".

Я предпочитаю слово "безопасность"; я чувствую, что это больше похоже на предотвращение несчастного случая, а не на злобность.

Ответ 2

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

То, что обычно подразумевается под "безопасностью" в таких дискуссиях, - это концепция модели защищенных объектов, то есть объектная модель, которую потребители не могут манипулировать целями, непреднамеренными оригинальным автором класса.

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

Защитите от чего?

Что касается мобильного кода (код, который может перемещаться между системами - апплеты, мидлеты, WebStart, RMI/JINI и т.д.), это очень важно. Применяется к классам и, в меньшей степени, доступным методам, предотвращает вредоносные реализации. Аналогично доступным полям, заметная статика. Если вы собираетесь писать код, который может стать частью библиотеки, вы должны быть в курсе этого.

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

Ответ 6

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

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

Ответ 7

Я предполагаю, что кто-то имел в виду, когда они сказали, что final делает ваш код более безопасным, так это то, что он препятствует будущим разработчикам продвигаться вперед и изменять значения, которые не предназначены для изменения, или наследуют от классов, которые не предназначены для быть расширенным (и вызывать непредсказуемые результаты в процессе). Ему нечего делать (напрямую) с помощью аутентификации.

Ответ 8

Я уверен, что final - это конструктивная конструкция, так же, как модификаторы доступа находятся в объявлениях классов - это способ выражения и применения дизайна.

Ответ 9

Это больше касается "изменения" материала, а не "обеспечения". Конечные ключевые слова просто отбрасывают возможность изменения/модификации/расширения любого метода.

Ответ 10

Final также улучшает управление производительностью/памятью.

Ответ 11

Конечное ключевое слово обычно используется для сохранения неизменности. Использовать final для классов или методов - это предотвращение нарушения связей между методами. Например, предположим, что реализация некоторого метода класса X предполагает, что метод M будет вести себя определенным образом. Объявление X или M как final предотвратит переопределение производных классов таким образом, чтобы заставить X вести себя некорректно. Он защищает объекты и методы от манипулирования. Но что касается цели криптографии, использование ключевого слова final не является решением

Ответ 12

Ключевое слово "final" действительно имеет некоторые последствия для безопасности. Представьте, что вы разрабатываете безопасную систему, которая имеет службу, которая, учитывая строку, делает что-то тогда и только тогда, когда строка действительна. Вы можете написать:

public void doSomethingUseful(String argument) {
    checkValidity(argument);
    /* prepare to do something useful... preparation takes a bit of time! */
    reallyDoTheUsefulTask(argument);
}

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

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