Flask - 上传到 S3/Google Cloud 时是否需要使用 secure_filename()?

tza*_*azo 6 werkzeug flask

在文件上传的 Flask 文档中,他们建议在存储文件之前使用 来secure_filename()清理文件的名称。

\n\n

这是他们的例子:

\n\n
uploaded_file = request.files[\'file\']\nif uploaded_file:\n    filename = secure_filename(uploaded_file.filename) # <<<< note the use of secure_filename() here\n    file.save(os.path.join(app.config[\'UPLOAD_FOLDER\'], filename))\n    return redirect(url_for(\'display_file\',\n                            filename=filename))\n
Run Code Online (Sandbox Code Playgroud)\n\n

文档说:

\n\n
\n

现在的问题是,有一个名为\xe2\x80\x9cnever trust user\n input\xe2\x80\x9d 的原则。对于上传文件的文件名也是如此。所有提交的表单数据都可以伪造,并且文件名可能很危险。目前请记住:在将文件名直接存储到文件系统之前,始终使用该函数来保护文件名。

\n
\n\n

对于异地存储(S3 或 Google Cloud),我不会使用 Flask 将文件存储在 Web 服务器上。相反,我将重命名上传文件(使用我自己的 UUID),然后将其上传到其他地方。

\n\n

例子:

\n\n
blob = bucket.blob(\'prompts/{filename}\'.format(filename=uuid.uui4()))\nblob.upload_from_string(uploaded_file.read(), content_type=uploaded_file.content_type)\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下,我认为您不需要先调用,对吗secure_filename()

\n\n

似乎因为我(a)将文件的内容读入字符串,然后(b)使用我自己的文件名,所以我的用例不易受到目录遍历或流氓命令类型攻击(例如),但"../../../../home/username/.bashrc"我\我不是100%确定。

\n

v25*_*v25 6

你是对的。

secure_filename仅当您使用 的值构建指向您的文件系统的文件路径时才需要使用该函数request.files['file'].filename- 例如作为 的参数os.path.join

由于您使用 UUID 作为文件名,因此用户输入值无论如何都会被忽略。

secure_filename即使没有 S3,如果您使用 UUID 作为本地文件系统上文件路径的文件名段,也不使用它也是安全的。例如:

uploaded_file = request.files['file']
if uploaded_file:
    file_uuid = uuid.uuid4()
    file.save(os.path.join(app.config['UPLOAD_FOLDER'], file_uuid))
    # Rest of code
Run Code Online (Sandbox Code Playgroud)

无论哪种情况,您都可以将 UUID 存储在数据库中的某个位置。是否将最初提供的request.files['file'].filename值与它一起存储是您的选择。

如果您希望用户在上传文件时看到文件的原始名称,这可能是有意义的。在这种情况下,无论如何运行该值绝对是明智的secure_filename,因此永远不会出现前端向用户显示包含名为的文件的列表的情况../../../../ohdear.txt


secure_filename文档字符串还指出了一些其他功能:

向它传递一个文件名,它将返回它的安全版本。然后可以将该文件名安全地存储在常规文件系统上并传递给 :func: os.path.join。返回的文件名是纯 ASCII 字符串,以实现最大的可移植性。在 Windows 系统上,该函数还确保该文件不以特殊设备文件之一命名。

>>> secure_filename("My cool movie.mov")
'My_cool_movie.mov'
>>> secure_filename("../../../etc/passwd")
'etc_passwd'
>>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
'i_contain_cool_umlauts.txt'
Run Code Online (Sandbox Code Playgroud)