Контрольный список загрузки изображений 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";
}
Любые новые советы приветствуются:)
Ответы
Ответ 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
Ответ 4
Возможно, вы захотите запустить "is_uploaded_file" в $_FILES ['my_files'] ['tmp_name']. См. http://php.net/manual/en/function.is-uploaded-file.php
Ответ 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 подходит лучше всего, потому что у него наименьшее количество проблем безопасности, и они довольно старые. Три из них являются критическими, но 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);
?>