Возможности безопасной загрузки изображений пользователей в PHP


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

1) Первый белый список допустимых расширений файлов в PHP, разрешающих только PNG, png, jpg, JPG и JPEG. Извлеките расширение файла пользователя с помощью такой функции, как как:

return end(explode(".", $filename));

Это должно помочь запретить пользователю загружать что-либо вредоносное, например.png.php . Если это пройдет, перейдите к шагу 2.

2) Запустите функцию php getimageize() в файле TMP. Через что-то вроде:

getimagesize($_FILES['userfile']['tmp_name']);

Если это не возвращает false, продолжайте.

3) Убедитесь, что файл .htaccess помещен в каталог загрузок, чтобы любые файлы в этом каталоге не могли анализировать файлы PHP:

php_admin_value engine Off

4) Переименуйте файл пользователя во что-то заранее определенное. Т.Е.

$filename = 'some_pre_determined_unique_value' . $the_file_extension;

Это также поможет предотвратить внедрение SQL, поскольку имя файла будет единственной переменной, определяемой пользователем, в любых используемых запросах.

Если я выполню вышеуказанное, насколько я все еще уязвим для атаки? Прежде чем принимать файл, я должен, надеюсь, 1) разрешить только jpg и png, 2) Проверить, что PHP говорит, что это допустимое изображение, 3) отключил каталог, в котором находятся изображения, от выполнения файлов.php и 4) переименовал файл пользователей во что-то уникальное.

Спасибо,

Author: flight643, 2010-09-05

3 answers

Что касается имен файлов, случайные имена, безусловно, являются хорошей идеей и избавляют от многих головных болей.

Если вы хотите полностью убедиться в чистоте содержимого, рассмотрите возможность использования GD или ImageMagick для копирования входящего изображения 1:1 в новое пустое изображение.

Это немного снизит качество изображения, поскольку содержимое сжимается дважды, но при этом будет удалена любая информация EXIF, присутствующая в исходном изображении. Пользователи часто даже не знают, сколько информации помещается в метаданные раздел файлов JPG! Информация о камере, положение, время, используемое программное обеспечение... Для сайтов, на которых размещаются изображения, рекомендуется удалять эту информацию для пользователя.

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

 20
Author: Pekka 웃, 2010-09-04 22:24:41

Что касается вашего номера 2), не просто проверяйте наличие FALSE. getimagesize также вернет тип mime изображения. Это, безусловно, более безопасный способ проверить правильный тип изображения, чем просмотр типа mime, предоставляемого клиентом:

$info = getimagesize($_FILES['userfile']['tmp_name']);
if ($info === FALSE) {
    die("Couldn't read image");
}
if (($info[2] !== IMAGETYPE_PNG) && ($info[2] !== IMAGETYPE_JPEG)) {
    die("Not a JPEG or PNG");
}
 4
Author: Marc B, 2010-09-05 03:31:35

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

 1
Author: Chris Laplante, 2010-09-04 22:00:39