Как достоверно определить тип загружаемого файла (текстовый или бинарный)?
У меня есть приложение, в котором пользователи должны иметь возможность загружать самые разные файлы, но мне нужно знать для каждого файла, могу ли я безопасно отобразить его текстовое представление в виде простого текста.
Использование Python-магии, как
m = Magic(mime=True).from_buffer(cgi.FieldStorage.file.read())
дает мне правильный тип MIME.
Но иногда MIME-тип для скриптов application/*
так просто ищу m.startswith('text/')
недостаточно.
Другой сайт предложил использовать
m = Magic().from_buffer(cgi.FieldStorage.file.read())
и проверка на 'text' in m
,
Будет ли второй подход достаточно надежным для сбора произвольных файловых загрузок или кто-то может дать мне другую идею?
Большое спасибо.
2 ответа
Какова ваша цель? Вы хотите настоящий тип пантомимы? Это важно по соображениям безопасности? Или это "приятно иметь"?
Проблема в том, что один и тот же файл может иметь разные типы пантомимы. Когда файл скрипта имеет надлежащий #!
header, python-magic может определить тип скрипта и сообщить вам. Если заголовок отсутствует, text/plain
может быть лучшее, что вы можете получить.
Это означает, что не существует общего волшебного решения "всегда будет работать" (несмотря на название модуля). Вам придется сесть и подумать, какую информацию вы можете получить, что это значит и как вы хотите к ней относиться.
Безопасным решением было бы создать список типов mime, которые вы принимаете, и проверить их с помощью:
allowed_mime_types = [ ... ]
if m in allowed_mime_types:
Это означает, что принимаются только идеальные совпадения. Это также означает, что ваш сервер отклонит допустимые файлы, которые по какой-то причине не имеют правильного типа MIME (отсутствует заголовок, магия не смогла распознать файл, вы забыли упомянуть тип MIME в своем списке).
Или, говоря иначе: зачем вы проверяете тип mime файла, если вас это не волнует?
[ПРАВКА] Когда вы говорите
Мне нужно знать для каждого файла, могу ли я безопасно отобразить его текстовое представление в виде простого текста.
тогда это не так просто, как кажется. Прежде всего, в "текстовых" файлах не хранится кодировка, поэтому вам необходимо знать кодировку, которую использовал пользователь при создании файла. Это не тривиальная задача. Для этого есть эвристика, но при использовании кодировок, таких как ISO 8859-1 и 8859-15 (последние обозначаются символом евро), они становятся проблематичными.
Чтобы это исправить, вам нужно будет заставить своих пользователей либо сохранять текстовые файлы в определенной кодировке (UTF-8
в настоящее время является лучшим выбором) или вам нужно предоставить форму, в которую пользователи должны будут вставить текст.
При использовании формы пользователь может видеть, правильно ли закодирован текст (они видят его на экране), он может решить любые проблемы, и вы можете убедиться, что браузер отправляет вам текст, закодированный с помощью UTF-8.
Если вы не можете этого сделать, ваш единственный выбор - проверить наличие байтов ниже 0x20 на входе, за исключением \r
, \n
а также \t
, Это довольно хорошая проверка для "это текстовый документ".
Но когда пользователи используют умляуты (например, когда вы пишете приложение, которое используется во всем мире), этот подход в конечном итоге потерпит неудачу, если вы не сможете применить определенную кодировку на стороне пользователя (чего вы, вероятно, не можете, поскольку вы не доверяете пользователь).
[EDIT2] Поскольку это необходимо для проверки фактического исходного кода: если вы хотите убедиться, что исходный код является "безопасным", проанализируйте его. Большинство языков позволяют анализировать код, фактически не выполняя его. Это даст вам некоторую реальную информацию (потому что парсеры знают, что искать), и вам не нужно будет делать дикие догадки:-)
Поиграв немного, я обнаружил, что могу Magic(mime_encoding=True)
Результаты!
Я запустил простой скрипт в своей папке Dropbox и сгруппировал результаты как по кодировке, так и по расширению, чтобы проверить наличие ошибок.
Но это выглядит довольно полезным, если искать 'binary' in encoding
,
Я думаю, что я буду держаться за это, но спасибо вам всем.