我的代码是否阻止目录遍历? [英] Does my code prevent directory traversal?

查看:192
本文介绍了我的代码是否阻止目录遍历?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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.gifhttp://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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆