在序列化程序 Django 中验证文件扩展名的安全方法

我创建了一个可以存储产品图像的应用程序。在数据库中,我只存储指定文件夹中保存的图像的方向。在我的序列化程序中,我需要验证文件名并检查扩展名是否是照片扩展名。我在下面写了这样的东西,这是检查它的最好方法吗?有没有更安全的方法?

ALLOWED_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "bmp", "gif"]

class ProductImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductImage
        fields = [...]

class ProductSerializer(serializers.ModelSerializer):
    images = ProductImageSerializer(many=True, read_only=True)

    class Meta:
        model = Product
        fields = [..., 'images']

    def create(self, validated_data):
        ...

        for file in self.context['request'].FILES.getlist('images'):
            validate_extension(file.name)
            ...

        return item

def validate_extension(filename):
    extension = os.path.splitext(filename)[1].replace(".", "")
    if extension.lower() not in ALLOWED_IMAGE_EXTENSIONS:
        raise serializers.ValidationError(
            (f'Invalid uploaded file type: {filename}'),
            code='invalid',
        )
stack overflow Safe way to validate file extension in serializer Django
原文答案

答案:

作者头像

您可以添加 2 个进一步的检查。首先,您可以验证文件的 mime 类型,例如在 linux 中使用 python-magic 包(Windows 为 python-magic-bin )。此外,您可以将文件大小与项目中所需的最大文件大小进行比较。

作者头像

您可以简单地添加 FileExttention 验证器


from django.db import models
from model_utils.models import TimeStampedModel
from .managers import ImageManager, PDFManager
from django.core.validators import FileExtensionValidator
import os

def upload_to_pdfs(instance, filename):
    return os.path.join(instance.owner.username, 'pdfs', filename)

def upload_to_images(instance, filename):
    return os.path.join(instance.owner.username, 'images', filename)

class Owner(TimeStampedModel):
    username = models.CharField(max_length=150, null=True, unique=True)

    def __str__(self):
        return self.username.__str__()

# Create your models here.
class PDFs(TimeStampedModel):
    owner = models.ForeignKey(to=Owner, on_delete=models.CASCADE, related_name="pdfs")
    filename = models.CharField(max_length=150, blank=True, null=True)
    path = models.FileField(upload_to=upload_to_pdfs,
                            validators=[FileExtensionValidator(allowed_extensions=['pdf'])])

    objects = PDFManager()

class Images(TimeStampedModel):
    owner = models.ForeignKey(to=Owner, on_delete=models.CASCADE, related_name="images")
    filename = models.CharField(max_length=150, blank=True, null=True)
    path = models.FileField(upload_to=upload_to_images,
                            validators=[
                                FileExtensionValidator(allowed_extensions=['png', 'jpeg', 'jpg', 'svg']),
                            ])

    objects = ImageManager()