【问题标题】:Django ImageField / FileField custom upload_to function, and securityDjango ImageField/FileField 自定义upload_to 功能,以及安全性
【发布时间】:2010-12-04 01:21:25
【问题描述】:

我有这样定义的模型的一部分:

logo_image = models.ImageField(upload_to=lambda i, fn: "logo_%s"%(fn), height_field="logo_image_height", width_field="logo_image_width")

并且对 upload_to 函数有疑问。

根据django's documentation for FileField.upload_to,第二个参数,filename 是“最初赋予文件的文件名。”

现在,了解了 HTTP、文件上传等,最终用户的客户端可以轻松伪造文件名。例如,终端客户端不能上传一个名为“/etc/passwd”的文件,然后如果我使用我的幼稚代码(lambda i, fn: "logo_%s"%(fn)),生成的文件不会上传到/etc/passwd吗?我需要转义filename 参数吗?

#using django's example of using full paths in settings module,
#MEDIA_ROOT="/tmp/media"
>>> os.path.join("/tmp/media/", "apple.jpg")
'/tmp/media/apple.jpg'
>>> os.path.join("/tmp/media/", "/etc/passwd")
'/etc/passwd'

感谢任何建议/答案/澄清。

编辑

看的重要方法是in files.py, near line 272

272         def get_directory_name(self):
273             return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
274     
275         def get_filename(self, filename):
276             return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
277     
278         def generate_filename(self, instance, filename):
279             return os.path.join(self.get_directory_name(), self.get_filename(filename))

定义一个自定义upload_to 替换generate_filename(),如here 所示:

226             if callable(upload_to):
227                 self.generate_filename = upload_to

那么,在save() method

89      def save(self, name, content, save=True):
90          name = self.field.generate_filename(self.instance, name)
91          self.name = self.storage.save(name, content)

并且返回的文件名被传递给存储类,最终调用_os.py util模块safe_join中的django替换函数。

这个功能似乎减轻了我的恐惧:

24    def safe_join(base, *paths):
25      """
26      Joins one or more path components to the base path component intelligently.
27      Returns a normalized, absolute version of the final path.
28  
29      The final path must be located inside of the base path component (otherwise
30      a ValueError is raised).
31      """

【问题讨论】:

  • 那么……你真的不需要回答这个问题吗?
  • 对不起 :) 似乎没有。现在只是在寻找验证(尽管有人再看一下)。
  • 如果您“回答自己的问题”然后将其标记为已回答,这样它就不会停留在未回答的列表中,这可能会更清楚。
  • 请将答案放入答案中。

标签: django security path filefield


【解决方案1】:

我想你已经回答了你自己的问题。需要澄清的一点是 os.path.join() 的工作方式是去掉前面的目录(根据与 os.path 相关的 Python 文档)。所以你在调用 os.path.join() 时观察到的行为与它的描述是一致的。

还有一点需要注意:get_filename() 函数调用 os.path.basename(),它将删除所有目录路径并仅返回基本名称。因此,如果没有 upload_to= 参数,就没有这种可能性的危险。

但是,如果您使用自己的 upload_to 函数覆盖 ImageField(),则不会调用此函数,最好调用 os.path.basename()。首先,它也会避免将文件名保存为完整的目录路径。因此,我发现最好在我的 upload_to 函数中调用 os.path.basename() 。有没有其他人遇到过这个问题?

更多详情请见:http://hustoknow.blogspot.com/2010/08/try-me-out.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-24
    • 2018-11-08
    • 2020-06-29
    • 2011-02-08
    • 2011-06-27
    • 2012-06-27
    • 2010-11-14
    相关资源
    最近更新 更多