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

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

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

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

static public final Thing [] VALUES = {...};

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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");
     }
}

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

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


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

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

Это неверно.

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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