我正在用Python编写一个简单的文件服务器。文件名由客户端提供,应视为不可信。如何验证它是否与当前目录(在其中或其任何子目录中)内的文件相对应?会是这样的:
pwd=os.getcwd()
if os.path.commonpath((pwd,os.path.abspath(filename))) == pwd:
open(filename,'rb')
足够?
答案 0 :(得分:3)
使用os.path.realpath
将文件名转换为规范路径,获取目录部分,并查看当前目录(以规范形式)是否为前缀:
import os, os.path
def in_cwd(fname):
path = os.path.dirname(os.path.realpath(fname))
return path.startswith(os.getcwd())
通过将fname
转换为规范路径,我们处理包含../
的符号链接和路径。
<强>更新强>
不幸的是,上面的代码有点问题。例如,
'/a/b/cd'.startswith('/a/b/c')
返回True
,但我们肯定不想要这种行为!幸运的是,有一个简单的解决方法:我们只需要在执行前缀测试之前将os.sep
附加到路径。新版本还通过os.path.normcase
处理任何操作系统路径名不区分大小写的问题。
import os, os.path
def clean_dirname(dname):
dname = os.path.normcase(dname)
return os.path.join(dname, '')
def in_cwd(fname):
cwd = clean_dirname(os.getcwd())
path = os.path.dirname(os.path.realpath(fname))
path = clean_dirname(path)
return path.startswith(cwd)
感谢DSM指出前一段代码中的缺陷。
这是一个效率更高的版本。它使用os.path.commonpath
,它比附加os.sep
和执行字符串前缀测试更强大。
def in_cwd(fname):
cwd = os.path.normcase(os.getcwd())
path = os.path.normcase(os.path.dirname(os.path.realpath(fname)))
return os.path.commonpath((path, cwd)) == cwd