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

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

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

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

Это мой script:

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

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

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

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

Ответ 5

Создайте новый файл .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 + забыть о проверке типов, содержимого и т.д.

Ответ 6

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

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

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

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

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


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

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

  • GD (6 уязвимостей)
  • ImageMagick (44 уязвимости)
  • Gmagick (12 уязвимостей)

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

Я использую 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);
        ?>