Контрольный список безопасности загрузки изображений PHP - PullRequest
61 голосов
/ 12 ноября 2010

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

  • Отключить запуск 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("Y-m-d").'/' ;

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

Любые новые советы приветствуются:)

Ответы [ 11 ]

33 голосов
/ 12 ноября 2010

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

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

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

12 голосов
/ 12 ноября 2010

Для проверки безопасности файлов изображений я могу представить 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

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

7 голосов
/ 07 февраля 2013

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

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

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

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

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

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

Самое безопасное решение:

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

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

6 голосов
/ 04 августа 2012

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

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

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

6 голосов
/ 12 ноября 2010

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

5 голосов
/ 18 февраля 2014

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

Вы можете определить тип контента, используя Функции 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 в качестве второго варианта.

2 голосов
/ 28 февраля 2016

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

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

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

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

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

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

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

2 голосов
/ 23 апреля 2012

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

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

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

0 голосов
/ 17 июля 2017

Я использую 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);
        ?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...