我的代码是否阻止目录遍历? [英] Does my code prevent directory traversal?
问题描述
Python WSGI应用程序中的以下代码段对目录遍历安全吗?它将读取作为参数传递的文件名,并返回命名文件.
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
我将应用程序安装在http://localhost:8000/file/{file}
下,并使用URL http://localhost:8000/file/../alarm.gif
和http://localhost:8000/file/%2e%2e%2falarm.gif
发送了请求.但是我的任何尝试都没有传递(现有)文件.那么我的代码已经可以避免目录遍历了吗?
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?
新方法
以下代码似乎阻止目录遍历:
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
推荐答案
您的代码不会阻止目录遍历.您可以使用 os.path 模块进行防范.
Your code does not prevent directory traversal. You can guard against this with the os.path module.
>>> import os.path
>>> os.curdir
'.'
>>> startdir = os.path.abspath(os.curdir)
>>> startdir
'/home/jterrace'
startdir
现在是绝对路径,您不想让该路径超出该范围.现在,假设我们从用户那里得到了一个文件名,他们给了我们恶意的/etc/passwd
.
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
.
>>> filename = "/etc/passwd"
>>> requested_path = os.path.relpath(filename, startdir)
>>> requested_path
'../../etc/passwd'
>>> requested_path = os.path.abspath(requested_path)
>>> requested_path
'/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.
>>> os.path.commonprefix([requested_path, startdir])
'/'
您可以在代码中进行检查.如果commonprefix函数返回的路径不是以startdir
开头,则该路径无效,您不应返回其内容.
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:
import os
def is_directory_traversal(file_name):
current_directory = os.path.abspath(os.curdir)
requested_path = os.path.relpath(file_name, start=current_directory)
requested_path = os.path.abspath(requested_path)
common_prefix = os.path.commonprefix([requested_path, current_directory])
return common_prefix != current_directory
这篇关于我的代码是否阻止目录遍历?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!