Python 获取错误“;可疑文件操作“;Django版本后,从Django:3.1.8更新Django:3.1.9

Python 获取错误“;可疑文件操作“;Django版本后,从Django:3.1.8更新Django:3.1.9,python,python-3.x,django,django-models,Python,Python 3.x,Django,Django Models,在更新到Django:3.1.9后,我发现这个错误,在Django:3.1.8上,它工作正常。 我有一个带有文件字段的文件模型,如下所示: class JobFiles(BaseModel): category = models.CharField(max_length=50, choices=FILE_CATEGORY) job_file = models.FileField('JobFile', upload_to=user_directory_path) 我指定了uplo

在更新到Django:3.1.9后,我发现这个错误,在Django:3.1.8上,它工作正常。

我有一个带有文件字段的文件模型,如下所示:

class JobFiles(BaseModel):
    category = models.CharField(max_length=50, choices=FILE_CATEGORY)
    job_file = models.FileField('JobFile', upload_to=user_directory_path)
我指定了upload_to选项,以便每个类别的上载方式不同:

def user_directory_path(instance, filename):
    import uuid
    if not instance.job_file_name:
        instance.job_file_name = filename
    if instance.category == 'Job Card':
        return f'job_card/{uuid.uuid4()}'
    if instance.category == 'Photos':
        return f'job_card/photos/{uuid.uuid4()}'
    if instance.category == 'Other':
        return f'job_card/other/{uuid.uuid4()}'
    return f'job_card/other/{uuid.uuid4()}'
生成错误的代码(仔细检查文件是否存在,并将其包装在文件对象中):

我得到的错误是:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python3.9/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/code/job_cards/views.py", line 311, in job_card_maintenance_create
    job_files.save()
  File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 753, in save
    self.save_base(using=using, force_insert=force_insert,
  File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 790, in save_base
    updated = self._save_table(
  File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 895, in _save_table
    results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 933, in _do_insert
    return manager._insert(
  File "/usr/local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1254, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1396, in execute_sql
    for sql, params in self.as_sql():
  File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1339, in as_sql
    value_rows = [
  File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1340, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1340, in <listcomp>
    [self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
  File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1291, in pre_save_val
    return field.pre_save(obj, add=True)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/fields/files.py", line 308, in pre_save
    file.save(file.name, file.file, save=False)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/fields/files.py", line 87, in save
    name = self.field.generate_filename(self.instance, name)
  File "/usr/local/lib/python3.9/site-packages/django/db/models/fields/files.py", line 322, in generate_filename
    filename = validate_file_name(filename)
  File "/usr/local/lib/python3.9/site-packages/django/core/files/utils.py", line 8, in validate_file_name
    raise SuspiciousFileOperation("File name '%s' includes path elements" % name)

Exception Type: SuspiciousFileOperation at /job_cards/create/
Exception Value: File name '/tmp/a1134065293b47c1a054c8fc1481ec93.pdf' includes path elements
回溯(最近一次呼叫最后一次):
文件“/usr/local/lib/python3.9/site packages/django/core/handlers/exception.py”,第47行,在内部
响应=获取响应(请求)
文件“/usr/local/lib/python3.9/site packages/django/core/handlers/base.py”,第181行,在get响应中
响应=包装的回调(请求,*回调参数,**回调参数)
文件“/usr/local/lib/python3.9/site packages/django/contrib/auth/decorators.py”,第21行,在包装视图中
返回视图功能(请求,*args,**kwargs)
文件“/code/job\u cards/views.py”,第311行,在job\u card\u maintenance\u create中
作业\u文件。保存()
文件“/usr/local/lib/python3.9/site packages/django/db/models/base.py”,第753行,保存
self.save_base(使用=使用,强制插入=强制插入,
save_base中的文件“/usr/local/lib/python3.9/site packages/django/db/models/base.py”,第790行
更新=自我保存表格(
文件“/usr/local/lib/python3.9/site packages/django/db/models/base.py”,第895行,在保存表中
结果=self.\u do\u insert(cls.\u基本\u管理器,使用,字段,返回\u字段,原始)
文件“/usr/local/lib/python3.9/site packages/django/db/models/base.py”,第933行,插入
退货经理。\u插入(
文件“/usr/local/lib/python3.9/site packages/django/db/models/manager.py”,第85行,在manager\u方法中
返回getattr(self.get_queryset(),name)(*args,**kwargs)
文件“/usr/local/lib/python3.9/site packages/django/db/models/query.py”,第1254行,插入
return query.get\u编译器(using=using).execute\u sql(返回\u字段)
文件“/usr/local/lib/python3.9/site packages/django/db/models/sql/compiler.py”,第1396行,在execute\u sql中
对于sql,self.as_sql()中的参数为:
as_sql中的文件“/usr/local/lib/python3.9/site packages/django/db/models/sql/compiler.py”,第1339行
值_行=[
文件“/usr/local/lib/python3.9/site packages/django/db/models/sql/compiler.py”,第1340行,在
[self.prepare_值(字段,self.pre_保存值(字段,对象))用于字段中的字段]
文件“/usr/local/lib/python3.9/site packages/django/db/models/sql/compiler.py”,第1340行,在
[self.prepare_值(字段,self.pre_保存值(字段,对象))用于字段中的字段]
文件“/usr/local/lib/python3.9/site packages/django/db/models/sql/compiler.py”,第1291行,保存前
返回字段。预保存(obj,add=True)
文件“/usr/local/lib/python3.9/site packages/django/db/models/fields/files.py”,第308行,保存前
file.save(file.name,file.file,save=False)
文件“/usr/local/lib/python3.9/site packages/django/db/models/fields/files.py”,保存中第87行
name=self.field.generate_文件名(self.instance,name)
文件“/usr/local/lib/python3.9/site packages/django/db/models/fields/files.py”,第322行,位于generate_文件名中
filename=验证文件名(filename)
文件“/usr/local/lib/python3.9/site packages/django/core/files/utils.py”,第8行,验证文件名
引发可疑文件操作(“文件名“%s”包括路径元素“%name”)
异常类型:可疑文件操作位于/job\u cards/create/
异常值:文件名“/tmp/a1134065293b47c1a054c8fc1481ec93.pdf”包含路径元素
我的尝试: 降级至3.1.8(工程) 向FileField传递一个字符串可以工作,但是它不会执行upload\u to。
试图将文件保存在“基本”文件夹和“媒体”文件夹中(仍然收到相同的错误)

这是由于最近发布的CVE-2021-31542的缓解措施

我发现django的新缓解代码与项目自身的文件和图像文件默认行为不一致,即从您提供给构造函数的对象复制准确的文件名

对代码应用这样的更改应该可以修复它,就像它修复了我的代码一样:

     doc = '/tmp/mergedfile.pdf'
     with open(doc, mode='rb') as f:
-         job_files.job_file = File(f)
+         job_files.job_file = File(f, name=os.path.basename(doc))
          job_files.save()

编辑:django发行版(5月13日,2.23版,2.2.23版,3.1.11版,3.2.3版)中的错误现已修复。我也遇到过这个问题,但需要能够通过编程指定上载目录。此更改使得在传递文件名时无法将文件放入目录中。不过,仍然可以解决这个新问题通过指定自定义函数进行限制

下面是一个围绕此更改工作的提交示例:

+def get_invoice_dir(instance, filename):
+    return "dpnk-{}/{}".format(instance.campaign.pk, filename)
+
+
 @with_author
 class Invoice(StaleSyncMixin, AbstractOrder):
     """Faktura"""
@@ -103,14 +107,14 @@ class Invoice(StaleSyncMixin, AbstractOrder):
     )
     invoice_pdf = models.FileField(
         verbose_name=_(u"PDF faktury"),
-        upload_to=u"invoices",
+        upload_to=get_invoice_dir,
         max_length=512,
         blank=True,
         null=True,
     )
     invoice_xml = models.FileField(
         verbose_name=_("XML faktury"),
-        upload_to="invoices",
+        upload_to=get_invoice_dir,
         max_length=512,
         blank=True,
         null=True,
@@ -340,16 +344,13 @@ def create_and_send_invoice_files(sender, instance, created, **kwargs):
     if not instance.invoice_pdf or not instance.invoice_xml:
         invoice_data = invoice_gen.generate_invoice(instance)
         instance.total_amount = invoice_data.price_tax
-        filename = "dpnk-%s/%s" % (
-            instance.campaign.pk,
-            slugify(
-                "invoice_%s_%s_%s_%s"
-                % (
-                    instance.sequence_number,
-                    instance.company.name[0:40],
-                    instance.exposure_date.strftime("%Y-%m-%d"),
-                    uuid.uuid4(),
-                ),
+        filename = slugify(
+            "invoice_%s_%s_%s_%s"
+            % (
+                instance.sequence_number,
+                instance.company.name[0:40],
+                instance.exposure_date.strftime("%Y-%m-%d"),
+                uuid.uuid4(),
             ),
         )

    • 解决此问题的最佳方法是升级到Django 2.2.23或任何最新版本的Django,因为此回归已经修复:)


      感谢您的帮助该漏洞现已在django版本中修复,该版本于今天5月13日发布,版本为2.2.23、3.1.11、3.2.3
      +def get_invoice_dir(instance, filename):
      +    return "dpnk-{}/{}".format(instance.campaign.pk, filename)
      +
      +
       @with_author
       class Invoice(StaleSyncMixin, AbstractOrder):
           """Faktura"""
      @@ -103,14 +107,14 @@ class Invoice(StaleSyncMixin, AbstractOrder):
           )
           invoice_pdf = models.FileField(
               verbose_name=_(u"PDF faktury"),
      -        upload_to=u"invoices",
      +        upload_to=get_invoice_dir,
               max_length=512,
               blank=True,
               null=True,
           )
           invoice_xml = models.FileField(
               verbose_name=_("XML faktury"),
      -        upload_to="invoices",
      +        upload_to=get_invoice_dir,
               max_length=512,
               blank=True,
               null=True,
      @@ -340,16 +344,13 @@ def create_and_send_invoice_files(sender, instance, created, **kwargs):
           if not instance.invoice_pdf or not instance.invoice_xml:
               invoice_data = invoice_gen.generate_invoice(instance)
               instance.total_amount = invoice_data.price_tax
      -        filename = "dpnk-%s/%s" % (
      -            instance.campaign.pk,
      -            slugify(
      -                "invoice_%s_%s_%s_%s"
      -                % (
      -                    instance.sequence_number,
      -                    instance.company.name[0:40],
      -                    instance.exposure_date.strftime("%Y-%m-%d"),
      -                    uuid.uuid4(),
      -                ),
      +        filename = slugify(
      +            "invoice_%s_%s_%s_%s"
      +            % (
      +                instance.sequence_number,
      +                instance.company.name[0:40],
      +                instance.exposure_date.strftime("%Y-%m-%d"),
      +                uuid.uuid4(),
                   ),
               )