我喜欢用Python编写一个模板系统,它允许包含文件。
例如
This is a template You can safely include files with safe_include`othertemplate.rst`
如你所知,包括档案可能是危险的。例如,如果我在允许用户创建自己模板的web应用程序中使用模板系统,他们可能会执行以下操作
I want your passwords: safe_include`/etc/password`
因此,我必须将文件的包含限制为某些子目录中的文件(例如/home/user/templates
)
现在的问题是:如何检查/home/user/templates/includes/inc1.rst
是否在/home/user/templates
的子目录中?
下面的代码是否有效并且安全?
import os.path
def in_directory(file, directory, allow_symlink = False):
#make both absolute
directory = os.path.abspath(directory)
file = os.path.abspath(file)
#check whether file is a symbolic link, if yes, return false if they are not allowed
if not allow_symlink and os.path.islink(file):
return False
#return true, if the common prefix of both is equal to directory
#e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
return os.path.commonprefix([file, directory]) == directory
只要allow_symlink
是假的,我认为应该是安全的。如果用户能够创建这样的链接,那么允许符号链接当然会使其不安全。
更新-解决方案
如果中间目录是符号链接,则上面的代码不起作用。
要防止这种情况,必须使用realpath
,而不是abspath
。
更新:添加一个trailing/to目录来解决commonprefix()Reorx指出的问题。
这也使得allow_symlink
不必要,因为符号链接扩展到了它们真正的目的地
import os.path
def in_directory(file, directory):
#make both absolute
directory = os.path.join(os.path.realpath(directory), '')
file = os.path.realpath(file)
#return true, if the common prefix of both is equal to directory
#e.g. /a/b/c/d.rst and directory is /a/b, the common prefix is /a/b
return os.path.commonprefix([file, directory]) == directory
Python 3的
pathlib
模块使用其Path.parents属性使这一点变得简单。例如:然后:
realpath(path):返回指定文件名的规范路径,消除路径中遇到的任何符号链接(如果操作系统支持它们)。
在目录和子目录名上使用它,然后检查后者以前者开头。
许多建议方法的问题
如果要使用字符串比较或
os.path.commonprefix
方法测试目录父项,这些路径或相对路径很容易出现类似名称的错误。例如:/path/to/files/myfile
将使用许多方法显示为/path/to/file
的子路径。/path/to/files/../../myfiles
不会被许多方法显示为/path/myfiles/myfile
的父级。事实上,是的。Rob Dennis的previous answer提供了一种比较路径父代的好方法,而不会遇到这些问题。Python 3.4添加了
pathlib
模块,该模块可以以更复杂的方式执行此类路径操作,可以选择不引用底层操作系统。jme在another previous answer中描述了如何使用pathlib
来准确地确定一条路径是否是另一条路径的子路径。如果您不喜欢使用pathlib
(不知道为什么,它非常棒),那么Python 3.5在os.path
中引入了一个新的基于OS的方法,它允许您以类似的精确和无错误的方式执行路径父子检查,代码要少得多。Python 3.5的新特性
Python 3.5引入了函数
os.path.commonpath
。这是特定于运行代码的操作系统的方法。您可以通过以下方式使用commonpath
来准确地确定路径父代:精确一行
在Python3.5中,您可以将整个代码组合成一行if语句。这很难看,它包含了对
os.path.abspath
的不必要的重复调用,而且它绝对不符合PEP 8 79字符行长度准则,但是如果您喜欢这种类型的东西,请执行以下操作:相关问题 更多 >
编程相关推荐