Контрольный список загрузки изображений PHP

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

  • Отключите PHP от работы в папке загрузки с помощью .httaccess.
  • Не разрешать загрузку, если имя файла содержит строку «php».
  • Разрешить только расширения: jpg, jpeg, gif и png.
  • Разрешить только тип файла изображения.
  • Запретить изображение с двумя типами файлов.
  • Измените имя изображения.
  • Загрузите в подкаталог не корневой каталог.

Это мой сценарий:

$filename=$_FILES['my_files']['name']; $filetype=$_FILES['my_files']['type']; $filename = strtolower($filename); $filetype = strtolower($filetype); //check if contain php and kill it $pos = strpos($filename,'php'); if(!($pos === false)) { die('error'); } //get the file ext $file_ext = strrchr($filename, '.'); //check if its allowed or not $whitelist = array(".jpg",".jpeg",".gif",".png"); if (!(in_array($file_ext, $whitelist))) { die('not allowed extension,please upload images only'); } //check upload type $pos = strpos($filetype,'image'); if($pos === false) { die('error 1'); } $imageinfo = getimagesize($_FILES['my_files']['tmp_name']); if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') { die('error 2'); } //check double file type (image with comment) if(substr_count($filetype, '/')>1){ die('error 3') } // upload to upload direcory $uploaddir = 'upload/'.date("Ymd").'/' ; if (file_exists($uploaddir)) { } else { mkdir( $uploaddir, 0777); } //change the image name $uploadfile = $uploaddir . md5(basename($_FILES['my_files']['name'])).$file_ext; if (move_uploaded_file($_FILES['my_files']['tmp_name'], $uploadfile)) { echo "<img id=\"upload_id\" src=\"".$uploadfile."\"><br />"; } else { echo "error"; } 

Любые новые подсказки приветствуются 🙂

Повторно обработайте изображение с помощью GD (или Imagick) и сохраните обработанное изображение. Все остальные просто забавны для хакеров.

Изменить: И, как указывал rr, используйте move_uploaded_file() для любой загрузки.

Позднее редактирование. Кстати, вы хотите быть очень ограничительным в своей папке загрузки. Эти места являются одним из темных уголков, где происходит много подвигов. Это допустимо для любого типа загрузки и любого языка / сервера программирования. Проверьте https://www.owasp.org/index.php/Unrestricted_File_Upload

Для проверки безопасности файлов изображений я могу представить себе 4 уровня ценных бумаг. Они были бы:

  • Уровень 1: проверьте расширение (файл расширения заканчивается на)
  • Уровень 2: проверьте тип MIME ($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
  • Уровень 3: прочитайте первые 100 байт и проверьте, есть ли у них какие-либо байты в следующем диапазоне: ASCII 0-8, 12-31 (десятичный).
  • Уровень 4: проверьте магические числа в заголовке (первые 10-20 байт файла). Вы можете найти некоторые из байтов заголовков файлов отсюда: http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples

Примечание. Загрузка всего изображения будет медленной.

Предупреждение XSS

Еще одно очень важное замечание. Не загружайте и не загружайте все, что можно интерпретировать как HTML в браузере.

Поскольку файлы находятся в вашем домене, javascript, содержащийся в этом документе HTML, будет иметь доступ ко всем вашим куки-файлам, позволяя какую-то атаку XSS.

Сценарий атаки:

  1. Атакующий загружает HTML-файл с JS-кодом, который отправляет все файлы cookie на его сервер.

  2. Злоумышленник отправляет ссылку вашим пользователям по почте, PM или просто через iframe на своем или любом другом сайте.

Наиболее безопасное решение:

Сделать загруженный контент доступным только в субдомене или другом домене. Таким образом, файлы cookie не будут доступны. Это также один из советов по эффективности Google:

https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain

Возможно, вы захотите запустить «is_uploaded_file» в $ _FILES ['my_files'] ['tmp_name']. См. http://php.net/manual/en/function.is-uploaded-file.php

Создайте новый файл .htaccess в каталоге uploads и вставьте этот код:

 php_flag engine 0 RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml 

Просто не забудьте переименовать файлы u upload + забыть о проверке типов, содержимого и т. Д.

Я повторю что-то, что я разместил в связанном вопросе.

Вы можете определить тип контента, используя функции Fileinfo (mime_content_type () в предыдущих версиях PHP).

Выдержка из PHP-руководства по старшему расширению Mimetype, которое теперь заменено на Fileinfo:

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

getimagesize() также может делать хорошую работу, но большинство других проверок, которые вы выполняете, нонсенс. Например, почему строка php не разрешена в имени файла. Вы не собираетесь включать файл изображения в PHP-скрипт, просто потому, что его имя содержит строку php , не так ли?


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

Итак, какое расширение PHP лучше всего подходит для безопасного повторного создания образа? Я проверил сайт CVE . Я думаю, что применимое трио – это те расширения:

  1. GD (6 уязвимостей)
  2. ImageMagick (44 уязвимости)
  3. Gmagick (12 уязвимостей)

Из сравнения я думаю, что GD подходит лучше всего, потому что у него наименьшее количество проблем безопасности, и они довольно старые. Три из них критичны, но ImagMagick и Gmagick не работают лучше … ImageMagick кажется очень глючным (по крайней мере, когда дело доходит до безопасности), поэтому я выбираю Gmagick как второй вариант.

если безопасность очень важна, используйте базу данных для сохранения имени файла и переименованного имени файла, и здесь вы можете изменить расширение файла на somthing как .myfile и создать файл php для отправки изображения с заголовками. php может быть более безопасным, и вы можете использовать его в теге img как blow:

 <img src="send_img.php?id=555" alt=""> 

также проверяйте расширение файла EXIF ​​перед загрузкой.

Самый простой ответ, который позволяет пользователям безопасно загружать файлы на PHP : Всегда сохранять файлы за пределами вашего корня документа.

Например: Если ваш корневой каталог вашего документа /home/example/public_html , сохраните файлы в /home/example/uploaded .

Благодаря безопасному сохранению ваших файлов из-за того, что ваш веб-сервер напрямую выполняется, существует несколько способов сделать их доступными для ваших посетителей:

  1. Настройте отдельный виртуальный хост для обслуживания статического контента, который никогда не запускает скрипты PHP, Perl и т. Д.
  2. Загрузите файлы на другой сервер (например, дешевый VPS, Amazon S3 и т. Д.).
  3. Храните их на одном сервере и используйте PHP-скрипт для прокси-запросов, чтобы убедиться, что файл доступен только для чтения, а не для исполняемого файла.

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

Лучший способ защитить свой сайт при загрузке изображения пользователя – это сделать следующие шаги:

  • проверьте расширение изображения
  • проверьте размер изображения с помощью этой функции «getimagesize ()»
  • после этого вы можете использовать функцию "file_get_contents ()"
  • В конце вы должны вставить file_Content в свою базу данных, я думаю, что это лучший способ! Что вы думаете?

Для файла изображения вы также можете изменить разрешение файла после переименования, чтобы убедиться, что оно никогда не выполняется (rw-r-r–)

Я использую php-upload-script, который создает новый случайный 4-байтовый номер для каждого загруженного файла, затем XOR содержимое файла с этими 4 байтами (повторяя их так часто, как это необходимо) и, наконец, присоединяет 4 перед сохранением файла.

Для загрузки 4 байта необходимо снова отключить от файла, содержимое будет снова обработано с помощью XORed и результат будет отправлен клиенту.

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

Вот код, который я использую для этого:

Загрузить:

  <?php $outputfilename = $_POST['filename']; $inputfile = $_FILES["myblob"]["tmp_name"]; $tempfilename="temp.tmp"; if( move_uploaded_file($inputfile, $tempfilename) ) { $XORstring = random_bytes(4); $tempfile=fopen($tempfilename, "r"); $outputfile=fopen($outputfilename, "w+"); flock($outputfilename, LOCK_EX); fwrite($outputfilename, $XORbytes1); while ( $buffer = fread($tempfile, 4) ) { $buffer = $buffer ^ $XORstring; fwrite($outputfilename, $buffer); } flock($outputfilename, LOCK_UN); fclose($tempfile); fclose($outputfile); unlink($tempfilename); } exit(0); ?> 

Скачать:

  <?php $inputfilename = $_POST['filename']; $tempfilename = "temp.tmp"; $inputfile=fopen($inputfilename, "r"); $tempfile=fopen($tempfilename, "w+"); flock($tempfile, LOCK_EX); $XORstring = fread($inputfile, 4); while ( $buffer = fread($inputfile, 4) ) { $buffer = $buffer ^ $XORstring; fwrite($tempfile, $buffer); } flock($tempfile, LOCK_UN); fclose($inputfile); fclose($tempfile); readfile($tempfile); unlink($tempfile); exit(0); ?>