Java: почему не следует использовать clone() для защитного копирования?

В «Эффективной Java» (глава 7) говорится

Также обратите внимание, что мы не использовали метод клонирования Дейта для создания защитных копий. Поскольку Date не является окончательным, метод clone не гарантирует возврат объекта класса java.util.Date: он может возвращать экземпляр ненадежного подкласса, специально предназначенного для злонамеренных действий. Такой подкласс может, например, записывать ссылку на каждый экземпляр в частный статический список во время его создания и разрешать злоумышленнику доступ к этому списку. Это дало бы злоумышленнику полную свободу действий во всех случаях. Чтобы предотвратить такого рода атаки, не используйте метод клонирования для создания защитной копии параметра, тип которого является подклассом для недоверенных сторон.

Я не совсем понимаю его объяснение. Почему clone() не возвращает объект Date? Как экземпляр может быть ненадежным подклассом?


person Kyle    schedule 09.04.2015    source источник


Ответы (3)


Рассмотрим этот код:

public class MaliciousDate extends Date { /** malicious code here **/ }

public class SomeClass {
    public static void main(String[] args) {
        MaliciousDate someDate = new MaliciousDate();
        Date copyOfMaliciousDate = someDate;
        Date anotherDate = copyOfMaliciousDate.clone();
    }
}

Поскольку copyOfMaliciousDate имеет тип Date, вы можете вызвать clone(), и он вернет объект Date, но вызов clone для copyOfMaliciousDate приведет к выполнению кода, написанного в MaliciousDate классе clone(), поскольку экземпляр, хранящийся в copyOfMaliciousDate, является MaliciousDate .

person egracer    schedule 09.04.2015
comment
Очевидно, но почему это касается только clone()? Если вы не уверены, что реализации будут придерживаться контрактов методов, или даже подозреваете, что они будут явно вредоносными, вам не следует доверять любому переопределенному методу. Которые эффективно убивают полиморфизм и ООП для начала. Я, наверное, что-то упускаю. - person Oliver Gondža; 25.10.2017
comment
Сам не читал книгу, поэтому не уверен в полном контексте, просто сделал предположения, сделанные в отрывке, который сопровождал вопрос. Если бы мне пришлось угадывать, я бы сказал, что этот отрывок относится к библиотеке, которую вы реализуете для использования третьей стороной. Не используйте clone() для защитного копирования, если только ваш класс не является конечным классом. - person egracer; 26.10.2017

clone() считается неудачным экспериментом по ряду причин. В этом случае кто-то, передав Date, мог передать EvilDate extends Date, чей метод clone() скрытно вернул копию, которая все еще могла быть изменена кем-то другим.

person chrylis -cautiouslyoptimistic-    schedule 09.04.2015

Я не читал книгу, из которой вы цитировали, но этот абзац дает плохое обоснование и не предлагает никакой защиты от любых нападок.

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

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

  • Используйте отражение, чтобы получить доступ для чтения и записи практически ко всему, что помечено как приватное,
  • Возиться с загрузчиками классов, чтобы загрузить свои собственные версии классов,
  • Позвоните System.exit(), чтобы остановить вашу программу, и
  • Делайте все, что может делать ваша программа, например, запускайте другие программы или получайте доступ к файлам.

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

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

person Colonel Thirty Two    schedule 21.11.2019