我的应用程序的一部分要求客户端请求文件。现在,一个表现良好的客户只会请求可以安全提供的文件,但我不希望用户去提供"../../../creditCardInfo.xls"
. 保护文件名以确保不提供高于目录层次结构中某个点的文件的最佳实践/最简单方法是什么?第一个直觉是禁止文件名..
其中包含文件名,但这似乎......不完整且不令人满意。
当前关于 SO 文件名安全的问题集中在制作可写/可读的文件名,而不是确保访问不应访问的文件。
这似乎可行,只要open
使用与os.path.abspath
. 这种方法有什么缺陷吗?
import os
def is_safe(filename):
here = os.path.abspath(".")
there = os.path.abspath(filename)
return there.startswith(here)
>>> is_safe("foo.txt")
True
>>> is_safe("foo/bar/baz")
True
>>> is_safe("../../goodies")
False
>>> is_safe("/hax")
False
如果您在 UNIX 变体中运行,您可能需要一个chroot jail来防止在您的应用程序之外访问系统。
这种方法将避免您必须编写自己的代码来处理问题,并让您通过基础设施设置来处理它。如果您需要限制对应用程序中某些区域的访问,因为它会更改进程认为的系统根目录,这可能不合适。
这是我使用的方法,我认为它的好处是可以轻松控制对文件的访问,并防止路径操纵。
当用户上传文件时:
要获取文件:
我认为您正在寻找一种方法来查找文件的规范(*)路径。即删除了..
,和符号链接。.
这就是角色os.path.realpath
>>> os.path.realpath(".")
'/home/sylvain'
>>> os.path.realpath("..")
'/home'
>>> os.path.realpath("./Documents/../..")
'/home'
realpath
将遵循符号链接并“减少”路径:
sylvain@daal:~$ ln -s /etc/password z
sylvain@daal:~$ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os.path
>>> os.path.realpath("z")
'/etc/password'
>>> os.path.realpath("z/..")
'/etc'
>>> os.path.realpath("./Documents/../z/..")
'/etc'
...而normpath
很容易被滥用:
>>> os.path.normpath("./Documents/../z/..")
'.'
获得规范名称后,您可以轻松检查用户是否应该有权访问请求的文件。通过与白名单进行比较来说。
(*) 一个文件可能有不同的路径,但只有一个规范路径。
有关更多信息,请参阅http://www.xyzws.com/Javafaq/what-is-the-difference-between-absolute-relative-and-canonical-path-of-file-or-directory/60。