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

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

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

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

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

спасибо,

11 ответов


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

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

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

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

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

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

кроме того, типы MIME-это то, что браузер пользователя утверждает, что файл. Удобно и полезно читать их и действовать на них в вашем коде, но это не безопасный метод, потому что любой, кто отправляет вам плохие файлы, легко подделает заголовки MIME. Это своего рода защита линии фронта, чтобы сохранить ваш код, который ожидает JPEG от блевотины на PNG, но если кто-то встроил вирус в a .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;

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


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

Я бы вирус/spy ware сканер, и пусть он сделает работу за вас.


вы можете использовать ниже код, который дает вам тип 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. ,..иногда это будет верно ("информация заголовка"). Это, в конечном счете, зависит от O. S.


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


какие типы файлов вы ожидали? Может быть, вы могли бы проверить, что он соответствует тому, что вы ожидаете, и отвергнуть все остальное.


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


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

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

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


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

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

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