Проверка Django ImageField (это достаточно)? - PullRequest
5 голосов
/ 24 апреля 2011

У меня много загруженного пользователем контента, и я хочу проверить, что загруженные файлы изображений на самом деле не являются вредоносными скриптами. В документации Django говорится, что ImageField:

"Унаследует все атрибуты и методы из FileField, но также проверяет, является ли загруженный объект допустимым изображением."

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

Будет ли ImageField иметь большое значение для обеспечения безопасности при загрузке изображений?

Ответы [ 2 ]

7 голосов
/ 26 октября 2011

Django проверяет изображение, загруженное через форму, используя PIL.См. https://code.djangoproject.com/browser/django/trunk/django/forms/fields.py#L519

try:
    # load() is the only method that can spot a truncated JPEG,
    #  but it cannot be called sanely after verify()
    trial_image = Image.open(file)
    trial_image.load()

    # Since we're about to use the file again we have to reset the
    # file object if possible.
    if hasattr(file, 'reset'):
        file.reset()

    # verify() is the only method that can spot a corrupt PNG,
    #  but it must be called immediately after the constructor
    trial_image = Image.open(file)
    trial_image.verify()
 ...
 except Exception: # Python Imaging Library doesn't recognize it as an image
    raise ValidationError(self.error_messages['invalid_image'])

Документация PIL гласит следующее о verify ():

Попытки определить, поврежден ли файл, без фактического декодирования данных изображения.Если этот метод обнаруживает какие-либо проблемы, он вызывает подходящие исключения.Этот метод работает только для вновь открытого изображения;если изображение уже было загружено, результат не определен.Кроме того, если вам нужно загрузить изображение после использования этого метода, вы должны снова открыть файл изображения.

Следует также отметить, что ImageField проверяется только при загрузке с использованием формы.Если вы сохраните модель самостоятельно (например, с помощью какого-либо сценария загрузки), проверка не будет выполнена.

1 голос
/ 24 апреля 2011

Еще один тест - команда file .Он проверяет наличие «магических чисел» в файле, чтобы определить его тип.В моей системе пакет file включает libmagic, а также оболочку на основе ctypes /usr/lib64/python2.7/site-packages/magic.py.Похоже, вы используете его следующим образом:

import magic

ms = magic.open(magic.MAGIC_NONE)
ms.load()
type =  ms.file("/path/to/some/file")
print type

f = file("/path/to/some/file", "r")
buffer = f.read(4096)
f.close()

type = ms.buffer(buffer)
print type

ms.close()

(код от здесь .)


Относительно вашего исходного вопроса: «Прочитайте источник, Люк. "

django / core / files / images.py:

"""
Utility functions for handling images.

Requires PIL, as you might imagine.
"""

from django.core.files import File

class ImageFile(File):
    """
    A mixin for use alongside django.core.files.base.File, which provides
    additional features for dealing with images.
    """
    def _get_width(self):
        return self._get_image_dimensions()[0]
    width = property(_get_width)

    def _get_height(self):
        return self._get_image_dimensions()[1]
    height = property(_get_height)

    def _get_image_dimensions(self):
        if not hasattr(self, '_dimensions_cache'):
            close = self.closed
            self.open()
            self._dimensions_cache = get_image_dimensions(self, close=close)
        return self._dimensions_cache

def get_image_dimensions(file_or_path, close=False):
    """
    Returns the (width, height) of an image, given an open file or a path.  Set
    'close' to True to close the file at the end if it is initially in an open
    state.
    """
    # Try to import PIL in either of the two ways it can end up installed.
    try:
        from PIL import ImageFile as PILImageFile
    except ImportError:
        import ImageFile as PILImageFile

    p = PILImageFile.Parser()
    if hasattr(file_or_path, 'read'):
        file = file_or_path
        file_pos = file.tell()
        file.seek(0)
    else:
        file = open(file_or_path, 'rb')
        close = True
    try:
        while 1:
            data = file.read(1024)
            if not data:
                break
            p.feed(data)
            if p.image:
                return p.image.size
        return None
    finally:
        if close:
            file.close()
        else:
            file.seek(file_pos)

Похоже, он просто читает файл по 1024 байта за раз, пока PIL не скажет, что это изображение, а затем остановится,Очевидно, что это не проверка целостности всего файла, так что это действительно зависит от того, что вы подразумеваете под «покрытием моей безопасности загрузки изображений»: незаконные данные могут добавляться к изображению и передаваться через ваш сайт.Кто-то может сделать ваш сайт DOS, загрузив много мусора или действительно большой файл.Вы можете быть уязвимы для атаки с помощью инъекций, если вы не проверите какие-либо загруженные подписи или не сделаете предположения о загруженном имени файла изображения.И так далее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...