PHP image upload security check list
я программирую скрипт для загрузки изображений в мое приложение. Достаточно ли следующих шагов безопасности, чтобы сделать приложение безопасным со стороны скрипта?
- отключить 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 ответов:
повторно обработайте изображение с помощью GD (или Imagick) и сохраните обработанное изображение. Все остальные просто
развлеченияскучно для хакеров.Edit: и как указал 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 (десятичный).
XSS предупреждение
еще одно очень важное замечание. Не подавайте / не загружайте ничего, что можно было бы интерпретировать как HTML в браузере.
поскольку файлы находятся в вашем домене, javascript, содержащийся в этом HTML-документе, будет иметь доступ ко всем вашим куки, что позволит использовать какую-то атаку XSS.
атаке:
злоумышленник загружает HTML-файл с кодом JS, который отправляет все файлы cookie на его сервер.
злоумышленник отправляет ссылку вашим пользователям по почте, PM или просто через iframe на своем или любом другом сайте.
самое безопасное решение:
сделать загруженный контент доступен лишь на поддомене или на другом домене. Таким образом файлы не будут доступны. Это также одна из производительности 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()может также сделать хорошую работу, но большинство других проверки вы выполняете бред. Например, почему stringphpНе допускается в filename. Вы не собираетесь включать файл изображения в php-скрипт, просто потому, что его имя содержитphpстроку, не так ли?
когда дело доходит до воссоздания изображений, в большинстве случаев это повысит безопасность... пока библиотека, которую вы используете, не уязвима.
Итак, какое расширение PHP лучше всего подходит для безопасного воссоздания образа? Я проверил CVE детали сайт. Я думаю, что применимое трио - это те расширения:
- GD (6 уязвимостей)
- ImageMagick (44 уязвимостей)
- Gmagick (12 уязвимостей)
из сравнения я думаю, что GD подходит лучше всего, потому что у него есть наименьшее количество проблем безопасности, и они довольно старые. Три из них являются критическими, но ImagMagick и Gmagick не работают лучше... ImageMagick кажется очень глючным (по крайней мере, когда речь заходит о безопасности), поэтому я выбираю Gmagick в качестве второго варианта.
если безопасность очень важна, используйте базу данных для сохранения имени файла и переименованного имени файла, и здесь вы можете изменить расширение файла на что-то подобное .myfile и сделать php файл для отправки изображения с заголовками . php может быть более безопасным, и вы можете использовать его в теге img, например blow:
<img src="send_img.php?id=555" alt="">также проверьте расширение файла с EXIF перед загрузкой.
самый простой ответ для разрешить пользователям безопасно загружать файлы в PHP - это: сохранять файлы вне корневого каталога документов.
например: если ваш корень документа
/home/example/public_htmlсохраните файлы/home/example/uploaded.когда ваши файлы безопасно выходят за пределы непосредственного выполнения вашим веб-сервером, есть несколько способов сделать их доступными для ваших посетителей:
- настройка отдельного виртуального хоста для обслуживания статического контента, который никогда не выполняет PHP, Perl и т. д. файлы сценариев.
- загрузите файлы на другой сервер (например, дешевый VPS, Amazon S3 и т. д.).
- держите их на одном сервере и используйте PHP-скрипт для прокси-запросов, чтобы файл был только читаемым, а не исполняемым.
однако, если вы идете с вариантами 1 или 3 в этом списке, и у вас есть уязвимость локального включения файла в вашем приложении, ваша форма загрузки файла может еще будь вектор атаки.
лучшие способ сохранить ваш сайт в безопасности, когда пользователь загружает изображение, чтобы сделать это шаги:
- проверьте расширение изображения
- проверьте размер изображения с помощью этой функции "getimagesize()"
- после этого вы можете использовать функцию "функции file_get_contents()"
- в конце вы должны вставить file_Content в вашу базу данных я думаю, что это лучший способ ! а каково Ваше мнение ?
для файла изображения вы также можете изменить разрешение файла после переименования, чтобы убедиться, что он никогда не выполняется (rw-r--r--)
Я использую php-upload-скрипт, который создает новый случайный 4-байтовый номер для каждого загруженного файла, затем XORs содержимое файла с этими 4 байтами (повторяя их так часто, как это необходимо), и, наконец, прикрепляет 4 байта к файлу перед его сохранением.
для загрузки, 4 байта должны быть отрезаны от файла снова, содержимое будет сохранено с ними снова и результат отправляется клиенту.
таким образом, я могу быть уверен, что файлы я сохраняю на сервер не будет исполняемым или иметь какое-либо потенциальное значение для любого приложения. Кроме того, мне не нужна дополнительная база данных для хранения имен файлов.
вот код, который я использую для этого:
загрузки:
<?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); ?>
Comments