I like to write a template system in Python, which allows to include files.
e.g.
This is a template You can safely include files with safe_include`othertemplate.rst`
As you know, including files might be dangerous. For example, if I use the template system in a web application which allows users to create their own templates, they might do something like
I want your passwords: safe_include`/etc/password`
So therefore, I have to restrict the inclusion of files to files which are for example in a certain subdirectory (e.g. /home/user/templates
)
The question is now: How can I check, whether /home/user/templates/includes/inc1.rst
is in a subdirectory of /home/user/templates
?
Would the following code work and be secure?
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
As long, as allow_symlink
is False, it should be secure, I think. Allowing symlinks of course would make it insecure if the user is able to create such links.
UPDATE - Solution The code above does not work, if intermediate directories are symbolic links. To prevent this, you have to use realpath
instead of abspath
.
UPDATE: adding a trailing / to directory to solve the problem with commonprefix() Reorx pointed out.
This also makes allow_symlink
unnecessary as symlinks are expanded to their real destination
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
Files are organized by storing related files in the same directory. In a hierarchical file system (that is, one in which files and directories are organized in a manner that resembles a tree), a directory contained inside another directory is called a subdirectory.
In a computer file system, a subdirectory is a directory that is contained another directory, called a parent directory. A parent directory may have multiple subdirectories.
This top level, or root directory, is given the name /. An example of a directory system is shown in Figure 35.1. In this case there are 5 sub-directories below the root level, these are bin, usr, etc, dev and user. Below the usr directory there are 3 sub-directories, these are lib, adm and bin.
Python 3's pathlib
module makes this straightforward with its Path.parents attribute. For example:
from pathlib import Path root = Path('/path/to/root') child = root / 'some' / 'child' / 'dir' other = Path('/some/other/path')
Then:
>>> root in child.parents True >>> other in child.parents False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With