Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check whether a directory is a sub directory of another directory

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 
like image 296
Simon Avatar asked Sep 28 '10 12:09

Simon


People also ask

What is the difference between directory and subdirectory?

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.

Which is a sub directory of Windows?

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.

What are the sub directories inside the root directory?

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.


1 Answers

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 
like image 73
jme Avatar answered Oct 03 '22 09:10

jme