Django ImageField / FileField自定义upload_to函数和安全性

时间:2009-10-05 19:06:30

标签: django security path filefield

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

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)),则不会将生成的文件上传到{{ 1}?我是否需要转义/etc/passwd参数?

filename

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

修改

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

#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'

定义自定义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(),如here所示:

generate_filename

然后,在save() method

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

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

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

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)

1 个答案:

答案 0 :(得分: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