Загрузка файла PHP: проверка на основе MIME или расширения?

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

Каковы плюсы и минусы этих двух способов проверки файлов?

И еще какие-то вопросы безопасности должны беспокоить меня?

В эти дни я полагался на MIME-тип, но на этот пост я получил ответ с наибольшим количеством голосов.

Проблемы с загрузкой файлов в PHP говорят:

Никогда не полагайтесь на тип MIME, представленный браузером!

4 ответа

Решение

Хорошо, так что для всех гениев здесь что-то вроде "ВИНТОВЫЕ РАСШИРЕНИЯ, ПРОВЕРИТЬ МИМ! FILEINFO RLZ!", Я подготовил некоторый учебник:

  1. Скачайте этот симпатичный логотип php, который я нарисовал
  2. Посмотрите это. Довольно мило, не правда ли?
  3. Переименуйте его в what_you_like.php
  4. Пройди через все свои классные шашки
  5. Запустить его

В заключение, вы никогда не должны когда-либо полагаться на MIME тип. Ваш веб-сервер не заботится о типе MIME, он определяет, что делать с помощью EXTENSION, в конечном итоге получившего отрицательное признание @Col. Ответ Шрапнели на самом деле правильный. Любая информация, предоставленная вам чем-то проверяющим MIME, абсолютно не имеет отношения к вашему веб-серверу, когда дело доходит до исполнения.

РЕДАКТИРОВАТЬ: не столь необычный код, какой вы хотите, чтобы он открывал веб-сайт для этого типа атаки:

<?php

$mimetype = mime_content_type($_FILES['file']['tmp_name']);
if(in_array($mimetype, array('image/jpeg', 'image/gif', 'image/png'))) {
   move_uploaded_file($_FILES['file']['tmp_name'], '/whatever/something/imagedir/' . $_FILES['file']['name']);
   echo 'OK';

} else {
    echo 'Upload a real image, jerk!';
}

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

В среде * nix у вас есть утилита для проверки типа MIME данного файла, обычно расположенная в файле magic.mime (/usr/share/magic.mime или что-то подобное, в зависимости от вашей настройки).

Скопируйте / вставьте из magic.mime, чтобы вы поняли, как это работает в двух словах:

# Magic data for KMimeMagic (originally for file(1) command)
#
# Note on adding additional MIME types:
#
# [RFC2045,RFC2046] specifies that Content Types, Content Subtypes, Character
# Sets, Access Types, and conversion values for MIME mail will be assigned and
# listed by the IANA.
# http://www.iana.org/assignments/media-types/
#
# Any unregistered file type should be listed with a preceding x-, as in
# application/x-foo (RFC2045 5.1), or a x., as in application/x.foo (RFC4288
# 4.3).  Any non x-prefixed type should be registered with IANA and listed at
# the above address.  Any other behavior is a MIME standards violation!
#
# It is preferred that when a registered MIME type exists, that
# the registered Content-Type and Subtype be used to refer to a file of
# that type, so don't use application/x-zip when application/zip is
# registered.
#
# If an active RFC suggests that a MIME registration for a new type is in
# progress, make a note of it pointing to that RFC.
#
# The format is 4-5 columns:
#    Column #1: byte number to begin checking from, ">" indicates continuation
#    Column #2: type of data to match
#    Column #3: contents of data to match
#    Column #4: MIME type of result
#    Column #5: MIME encoding of result (optional)

Я свяжу вас со ссылкой, которая поможет вам в дальнейшей реализации на PHP (буквально 2 строки кода, как только вы закончите).

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

Fileinfo

Ни один из них не подходит для точного определения типа файла. Причины - * Расширение - пользователь может легко изменить расширение, просто переименовав файл. * MIME-тип. Чтобы изменить MIME-тип, некоторые надстройки / расширения могут делать это так, как они поступают со стороны клиента (так что их можно изменить перед отправкой на сервер), а не сгенерировать сервером.

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

Большую часть времени нам нужно убедиться, что загруженный файл не должен выполняться. По этой причине вам нужно быть уверенным в том, как ваш сервер обрабатывает / выполняет файлы. - Если ваш сервер проверяет расширения для проверки, вам также необходимо убедиться, что вы не храните файл с расширением, которое может быть выполнено. - Если ваш сервер использует MIME-типы, помните о том, что MIME-тип, отправленный клиентом, и MIME-тип, используемый сервером для одного и того же файла, могут отличаться. Так что используйте ту же логику, которую использует ваш сервер, чтобы узнать mime-тип.

Mime-type не является надежным источником, потому что он отправляет из браузера (также любой может создать HTTP-запрос вручную). PHP не проверял эквивалентность расширения и моего типа (http://ru.php.net/manual/en/features.file-upload.post-method.php). Вы можете акцентировать HTTP-запрос с именем файла "image.php" и mime-типом "image/gif".

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

Другие вопросы по тегам