目录遍历
目录遍历 :是另外一种注入方式的攻击,在这种攻击中,恶意用户诱骗文件系统代码对Web服务器不应该访问的文件进行读取和/或写入操作。
例子可以是这样的,某个视图试图在没有仔细对文件进行防毒处理的情况下从磁盘上读取文件:
def dump_file(request):
filename = request.GET["filename"]
filename = os.path.join(BASE_PATH, filename)
content = open(filename).read()
# ...
尽管一眼看上去,视图通过 BASE_PATH
(通过使用 os.path.join
)限制了对于文件的访问,但如果攻击者使用了包含 ..
(两个句号,父目录的一种简写形式)的文件名,她就能够访问到 BASE_PATH
目录结构以上的文件。对她来说,发现究竟使用几个点号只是时间问题,比如这样:../../../../../etc/passwd
。
任何不做适当转义地读取文件操作,都可能导致这样的问题。 允许 写 操作的视图同样容易发生问题,而且结果往往更加可怕。
这个问题的另一种表现形式,出现在根据URL和其他的请求信息动态地加载模块。 一个众所周知的例子来自于Ruby on Rails。 在2006年上半年之前,Rails使用类似于 http://example.com/person/poke/1
这样的URL直接加载模块和调用函数。 结果是,精心构造的URL,可以自动地调用任意的代码,包括数据库的清空脚本。
解决方案
如果你的代码需要根据用户的输入来读写文件,你就需要确保,攻击者不能访问你所禁止访问的目录。
备注
不用多说,你 永远 不要在编写可以读取任何位置上的文件的代码!
Django内置的静态内容视图是做转义的一个好的示例(在 django.views.static
中)。这是相关代码:
import os
import posixpath
# ...
path = posixpath.normpath(urllib.unquote(path))
newpath = ''
for part in path.split('/'):
if not part:
# strip empty path components
continue
drive, part = os.path.splitdrive(part)
head, part = os.path.split(part)
if part in (os.curdir, os.pardir):
# strip '.' and '..' in path
continue
newpath = os.path.join(newpath, part).replace('\\', '/')
Django不读取文件(除非你使用 static.serve
函数,但也受到了上面这段代码的保护),因此这种危险对于核心代码的影响就要小得多。
更进一步,URLconf抽象层的使用,意味着不经过你明确的指定,Django 决不会 装载代码。 通过创建一个URL来让Django装载没有在URLconf中出现的东西,是不可能发生的。