如何安全地将任意深度路径传递给webapp(在本例中为Flask)?

pin*_*ept 6 python web-applications werkzeug flask

我有一个表单,在发布表单时将字符串发送到我的Flask应用程序.字符串是一个文件路径,所以我想确保它不包含任何令人讨厌的东西,比如../../../etc/passwd.Flask使用的Werkzeug有一个方便的功能secure_filename,可以从文件名中删除令人讨厌的东西.不幸的是,当输入一个完整的路径时templates/example.html,它将转换/_,所以我们最终得到templates_example.html.

那么,将路径分割成级别似乎是明智的,所以我分别发送templatesexample.html在服务器上再次将它们连接在一起.这很有效,除了路径可以任意深度.我可以串起来dir1/dir2/dir3/dir4,希望没有人比我更深入dir4,但这似乎是愚蠢的.

处理未知深度路径验证的正确方法是什么?验证方式不同?以不同方式发送数据?以不同方式编码路径,然后在服务器上解码它?

Arm*_*her 9

对于像这样的情况safe_join,如果用户试图离开路径,Flask 会引发404:

>>> safe_join('/foo/bar', 'test')
'/foo/bar/test'
>>> safe_join('/foo/bar', 'test/../other_test')
'/foo/bar/other_test'
>>> safe_join('/foo/bar', 'test/../../../etc/htpassw')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mitsuhiko/Development/flask/flask/helpers.py", line 432, in safe_join
    raise NotFound()
werkzeug.exceptions.NotFound: 404: Not Found
Run Code Online (Sandbox Code Playgroud)


Phi*_*ham 2

您可以使用werkzeug.routing.PathConverter来处理任意路径,如下所示:

from flask import Flask
app = Flask(__name__)

@app.route("/arbitrary/<path:my_path>")
def arbitrary_path(my_path):
    return my_path

if __name__ == "__main__":
    app.run()
Run Code Online (Sandbox Code Playgroud)

通过上面过于简化的示例,您可以看到如果您访问http://127.0.0.1:5000/arbitrary/dir1/dir2/dir3/dir4它就会返回dir1/dir2/dir3/dir4,如果您访问http://127.0.0.1:5000/arbitrary/dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9/dir10它就会返回dir1/dir2/dir3/dir4/dir5/dir6/dir7/dir8/dir9/dir10

  • 这是您的浏览器解析路径。路径转换器本身不会清理路径。请参阅下面我的回答,了解该问题的正确解决方案。 (2认同)