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

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

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

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

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

Спасибо,

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

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

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

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

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

Изменить: я вижу, что в PHP есть некоторые инструменты для этого.

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

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

Посмотрите на функции Fileinfo, если вы используете 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 distros включают команду с именем file которая при запуске в файле выводит свой тип. Он имеет выход для вывода в формате для чтения (по умолчанию) или в MIME-формате. Вы можете заставить свой скрипт вызывать эту программу в загруженном файле и читать результат. Опять же, это не предпочтительный подход. Если вы работаете в Windows, эта утилита доступна через Cygwin.

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

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

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

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

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

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