我的代码是否阻止目录遍历?
来自 Python WSGI 应用程序的以下代码片段可以安全地进行目录遍历吗?它读取作为参数传递的文件名并返回指定的文件。
file_name = request.path_params["file"]
file = open(file_name, "rb")
mime_type = mimetypes.guess_type(file_name)[0]
start_response(status.OK, [('Content-Type', mime_type)])
return file
我将应用程序安装在 http://localhost:8000/file/{file}
下,并使用 URL http://localhost:8000/file/../alarm.gif 发送请求
和 http://localhost:8000/file/%2e%2e%2falarm.gif
。但我的所有尝试都没有提供(现有)文件。那么我的代码已经可以安全地避免目录遍历了吗?
新方法
下面的代码似乎可以阻止目录遍历:
file_name = request.path_params["file"]
absolute_path = os.path.join(self.base_directory, file_name)
normalized_path = os.path.normpath(absolute_path)
# security check to prevent directory traversal
if not normalized_path.startswith(self.base_directory):
raise IOError()
file = open(normalized_path, "rb")
mime_type = mimetypes.guess_type(normalized_path)[0]
start_response(status.OK, [('Content-Type', mime_type)])
return file
Is the following code snippet from a Python WSGI app safe from directory traversal? It reads a file name passed as parameter and returns the named file.
file_name = request.path_params["file"]
file = open(file_name, "rb")
mime_type = mimetypes.guess_type(file_name)[0]
start_response(status.OK, [('Content-Type', mime_type)])
return file
I mounted the app under http://localhost:8000/file/{file}
and sent requests with the URLs http://localhost:8000/file/../alarm.gif
and http://localhost:8000/file/%2e%2e%2falarm.gif
. But none of my attempts delivered the (existing) file. So is my code already safe from directory traversal?
New approach
It seems like the following code prevents directory traversal:
file_name = request.path_params["file"]
absolute_path = os.path.join(self.base_directory, file_name)
normalized_path = os.path.normpath(absolute_path)
# security check to prevent directory traversal
if not normalized_path.startswith(self.base_directory):
raise IOError()
file = open(normalized_path, "rb")
mime_type = mimetypes.guess_type(normalized_path)[0]
start_response(status.OK, [('Content-Type', mime_type)])
return file
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的代码不会阻止目录遍历。您可以使用 os.path 模块来防范这种情况。
startdir
现在是绝对路径,您不希望该路径超出该路径。现在假设我们从用户那里获取了一个文件名,他们给了我们恶意的/etc/passwd
。我们现在已将它们的路径转换为相对于我们的起始路径的绝对路径。由于它不在起始路径中,因此它没有起始路径的前缀。
您可以在代码中检查这一点。如果 commonprefix 函数返回的路径不以
startdir
开头,则该路径无效,您不应返回内容。上面的内容可以包装为静态方法,如下所示:
Your code does not prevent directory traversal. You can guard against this with the os.path module.
startdir
is now an absolute path where you don't want to allow the path to go outside of. Now let's say we get a filename from the user and they give us the malicious/etc/passwd
.We have now converted their path into an absolute path relative to our starting path. Since this wasn't in the starting path, it doesn't have the prefix of our starting path.
You can check for this in your code. If the commonprefix function returns a path that doesn't start with
startdir
, then the path is invalid and you should not return the contents.The above can be wrapped to a static method like so:
仅使用用户输入文件的基本名称:
os.path.basename
从路径中删除../
:Use only the base name of the user inputed file:
os.path.basename
strips../
from the path:这里有一个更简单的解决方案:
relpath 负责为我们规范化路径。如果相对路径以
..
开头,那么你就不允许它。There's a much simpler solution here:
relpath
takes care of normalising path for us. And if the relative path starts with..
, then you don't allow it.您可以使用 secure_filename 清理文件名。这将删除任何不需要的字符。
You can sanitize the filename using secure_filename. This will remove any unwanted characters.