我有一个像这样定义的模型的一部分:
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)
答案 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