Улучшает ли ключевое слово Java 'final' безопасность? - PullRequest
19 голосов
/ 21 января 2010

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

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

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

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

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

Ответы [ 12 ]

37 голосов
/ 21 января 2010

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

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

10 голосов
/ 21 января 2010

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

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

8 голосов
/ 21 января 2010

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

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

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

4 голосов
/ 21 января 2010

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

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

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

4 голосов
/ 21 января 2010

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

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

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

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

3 голосов
/ 21 января 2010

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

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

2 голосов
/ 21 января 2010

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

2 голосов
/ 21 января 2010

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

1 голос
/ 28 июля 2015

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

1 голос
/ 21 января 2010

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

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

...