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

Безопасные возможности загрузки изображений пользователей в 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 помещен в каталог uploads, так что любые файлы в этом каталоге не могут анализировать файлы 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) переименовал файл пользователя в нечто уникальный.

Спасибо,

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Что касается вашего номера 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");
}

Ответ 3

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