Почему общедоступный статический заключительный массив является дырой в системе безопасности?

Эффективный Java говорит:

//Потенциальная дыра в системе безопасности!

статическая общедоступная заключительная Вещь [] ОЦЕНИВАЕТ = {...};

Кто-то может сказать мне, какова дыра в системе безопасности?

37
задан mdma 16 May 2010 в 14:36
поделиться

7 ответов

Объявление статических конечных полей public обычно является отличительной чертой класса-константы. Это совершенно нормально для примитивных типов (ints, doubles и т.д.) и неизменяемых классов, таких как strings и java.awt.Color. С массивами проблема заключается в том, что даже если ссылка на массив постоянна, элементы массива все равно могут быть изменены, а поскольку это поле, изменения являются незащищенными, неконтролируемыми и обычно нежелательными.

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

53
ответ дан 27 November 2019 в 04:10
поделиться

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

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

2
ответ дан 27 November 2019 в 04:10
поделиться

В этом объявлении клиент может изменять Thing [0], Thing [1] и т. Д. (Т. Е. Элементы в массиве).

1
ответ дан 27 November 2019 в 04:10
поделиться

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

public class SafeSites {
    // a trusted class with permission to create network connections
    public static final String[] ALLOWED_URLS = new String[] {
        "http://amazon.com", "http://cnn.com"};

    // this method allows untrusted code to connect to allowed sites (only)
    public static void doRequest(String url) {
        for (String allowed : ALLOWED_URLS) {
            if (url.equals(allowed)) {
                 // send a request ...
            }
        }
    }
}

public class Untrusted {
     // An untrusted class that is executed in a security sandbox.

     public void naughtyBoy() {
         SafeSites.ALLOWED_URLS[0] = "http://myporn.com";
         SafeSites.doRequest("http://myporn.com");
     }
}

Как видите, ошибочное использование последнего массива означает, что ненадежный код может нарушить ограничение, что доверенный код / sandbox пытается навязать. В данном случае это явно проблема безопасности.

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


Эмбер сказала это в комментарии:

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

Это неверно.

Тот факт, что «плохой парень» может использовать исходный код / ​​байт-коды, чтобы определить, что частный существует и ссылается на массив, недостаточен для нарушения безопасности. Плохой парень также должен внедрить код в JVM, у которого есть необходимые разрешения для использования отражения. Это разрешение недоступно для ненадежного кода, работающего в (правильно реализованной) изолированной программной среде безопасности.

41
ответ дан 27 November 2019 в 04:10
поделиться

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

-- Эффективная Java, 2-е изд. (стр. 70)

15
ответ дан 27 November 2019 в 04:10
поделиться

Думаю, это просто означает всю эту историю с public vs private. Предполагается, что хорошей практикой является объявление локальных переменных приватными, а затем использование методов get и set, а не прямой доступ к ним. Это немного усложняет работу с ними вне вашей программы. Это все, насколько я знаю.

0
ответ дан 27 November 2019 в 04:10
поделиться

Потому что ключевое слово final гарантирует только значение ссылки (например, как место в памяти), но не содержимое в ней.

0
ответ дан 27 November 2019 в 04:10
поделиться
Другие вопросы по тегам:

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