Как я могу программно определить истинное расширение / тип файла?

StackOverflow https://stackoverflow.com/questions/481743

Вопрос

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

Есть ли способ определить истинное расширение / тип файла файла и убедиться, что это не другой тип файла, замаскированный другим расширением?

Существует ли отметка байта или какой-то уникальный идентификатор для каждого типа / расширения?

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

Спасибо,

Это было полезно?

Решение

Не на самом деле нет.

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

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

В своей программе я отправляю загруженное изображение в imagemagick в блоке try-catch, и если оно взрывается, то, я думаю, это было плохое изображение.Это следует считать небезопасным, поскольку я загружаю произвольные (предоставляемые пользователем) двоичные данные во внешнюю программу, что обычно является вектором атаки.здесь я верю, что imageMagick ничего не сделает с моей системой.

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

Редактировать:Я вижу, что в PHP есть несколько инструментов, которые сделают это за вас.

Кроме того, типы MIME — это то, что браузер пользователя называет файлом.Читать их и действовать в соответствии с ними в своем коде удобно и полезно, но это небезопасный метод, поскольку любой, отправляющий вам плохие файлы, легко подделает заголовки MIME.Это своего рода передовая защита, позволяющая защитить ваш код, ожидающий JPEG, от PNG, но если кто-то встроил вирус в .exe и назвал его JPEG, нет причин не подделать тип MIME.

Другие советы

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

Взгляните на Функции информации о файле если вы используете PHP 5.3+

$finfo = finfo_open(FILEINFO_MIME); 
$type = finfo_file($finfo, $filepath);
finfo_close($finfo);  

Альтернативно, проверьте mime_content_type для более старых версий.

$type = mime_content_type($filepath);

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

PHP имеет суперглобальный $_FILES (ФАЙЛЫ) в нем содержится такая информация, как размер и тип файла.Похоже, что тип берется из какого-то заголовка, а не из расширения, но я могу ошибаться.

Пример этого есть на сайт w3schools.

Я собираюсь проверить, можно ли это обмануть, когда у меня будет такая возможность.

Обновить:

Все остальные, вероятно, знали это, но $_FILES можно обмануть.Я смог определить это таким образом:

$arg = escapeshellarg( $_FILES["file"]["tmp_name"] );
system( "file $arg", $type );
echo "Real type:  " . $type;

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

это еще можно было подделать.Я бы позаботился о том, чтобы вы не могли (или не запускали) автоматически запускать файл, загруженный на сервер.

мне бы тоже иметь сканер вирусов/шпионов, и пусть он сделает всю работу за вас.

вы можете использовать приведенный ниже код, который дает вам тип MIME, если вы также изменили расширение

$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo $mime = finfo_file($finfo, $_FILES['userfile']['tmp_name']);
finfo_close($finfo);

Пользователи Windows:просто отредактируйте php.ini и раскомментируйте эту строку:

extension=php_fileinfo.dll

Не забудьте перезапустить Apache, чтобы новый php.ini вступил в силу.

В *nix вам говорят первые два байта файла (см. «магическое число»).В Windows... иногда это будет правдой («информация заголовка»).Это, в конечном счете, О.С.зависимый.

Исполняемые файлы обычно имеют «подпись» в первых байтах;Однако мне трудно точно определить, что на самом деле представляет собой тип файла.

Какие типы файлов вы ожидаете?Возможно, вы могли бы проверить, соответствует ли оно вашим ожиданиям, и отвергнуть все остальное.

Другие уже упоминали FileInfo, что, на мой взгляд, является правильным решением, но я добавлю это на тот случай, если вы по какой-то причине не сможете его использовать.Большинство (все?) дистрибутивов *nix включают команду под названием file что при запуске файла выводится его тип.Он имеет переключатель для вывода в удобочитаемом формате (по умолчанию) или типе MIME.Вы можете заставить свой скрипт вызывать эту программу для загруженного файла и читать результат.Опять же, это не предпочтительный подход.Если вы используете Windows, эта утилита доступна через Cygwin.

Достаточно ли просто проверить тип MIME?Я предполагаю, что изменение расширения файла не меняет его тип MIME?

Является ли MIME-тип достаточно сильным индикатором, чтобы его можно было использовать здесь?

Спасибо за все ответы.

Достаточно ли просто проверить тип MIME?Я предполагаю, что изменение расширения файла не меняет его тип MIME?Является ли MIME-тип достаточно сильным индикатором, чтобы его можно было использовать здесь?

Это действительно зависит от того, как он используется.

  • Если вы предоставляете загрузку и скачивание, то ничего не имеет значения, поскольку оно не выполняется.
  • Если это обрабатывается веб-сервером, то это будет зависеть от того, как настроен веб-сервер, хотя и с учетом большинства остальных комментариев.
  • Если это изображение, оно либо будет отображаться, либо нет, либо станет целью эксплойтов библиотеки изображений.Но только те.
  • Что-то вроде PDF-файла может повлиять не на ваш сервер, а на компьютер человека, обращающегося к файлу.
  • Если он будет передан в функцию типа «system()», то мы вернемся к поведению ОС — как если бы он был «двойным щелчком мыши», и можно даже рассмотреть расширение файла.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top