最佳答案
我喜欢用 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
是 False,我认为它就应该是安全的。如果用户能够创建这样的链接,那么允许符号链接当然会使其不安全。
UPDATE - Solution
如果中间目录是符号链接,则上述代码不起作用。
为了防止这种情况,必须使用 realpath
而不是 abspath
。
更新: 添加一个尾随/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