Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Friday, December 11, 2015

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

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  

Answer by blaze for How to check whether a directory is a sub directory of another directory


os.path.realpath(path): Return the canonical path of the specified filename, eliminating any symbolic links encountered in the path (if they are supported by the operating system).

Use it on directory and subdirectory name, then check latter starts with former.

Answer by Andrew_1510 for How to check whether a directory is a sub directory of another directory


I would test the result from commonprefix against the filename to get a better answer, something like this:

def is_in_folder(filename, folder='/tmp/'):      # normalize both parameters      fn = os.path.normpath(filename)      fd = os.path.normpath(folder)        # get common prefix      commonprefix = os.path.commonprefix([fn, fd])      if commonprefix == fd:          # in case they have common prefix, check more:          sufix_part = fn.replace(fd, '')          sufix_part = sufix_part.lstrip('/')          new_file_name = os.path.join(fd, sufix_part)          if new_file_name == fn:              return True          pass      # for all other, it's False      return False  

Answer by Rob Dennis for How to check whether a directory is a sub directory of another directory


so, I needed this, and due to the criticisms about commonprefx, I went a different way:

def os_path_split_asunder(path, debug=False):      """      http://stackoverflow.com/a/4580931/171094      """      parts = []      while True:          newpath, tail = os.path.split(path)          if debug: print repr(path), (newpath, tail)          if newpath == path:              assert not tail              if path: parts.append(path)              break          parts.append(tail)          path = newpath      parts.reverse()      return parts      def is_subdirectory(potential_subdirectory, expected_parent_directory):      """      Is the first argument a sub-directory of the second argument?        :param potential_subdirectory:      :param expected_parent_directory:      :return: True if the potential_subdirectory is a child of the expected parent directory        >>> is_subdirectory('/var/test2', '/var/test')      False      >>> is_subdirectory('/var/test', '/var/test2')      False      >>> is_subdirectory('var/test2', 'var/test')      False      >>> is_subdirectory('var/test', 'var/test2')      False      >>> is_subdirectory('/var/test/sub', '/var/test')      True      >>> is_subdirectory('/var/test', '/var/test/sub')      False      >>> is_subdirectory('var/test/sub', 'var/test')      True      >>> is_subdirectory('var/test', 'var/test')      True      >>> is_subdirectory('var/test', 'var/test/fake_sub/..')      True      >>> is_subdirectory('var/test/sub/sub2/sub3/../..', 'var/test')      True      >>> is_subdirectory('var/test/sub', 'var/test/fake_sub/..')      True      >>> is_subdirectory('var/test', 'var/test/sub')      False      """        def _get_normalized_parts(path):          return os_path_split_asunder(os.path.realpath(os.path.abspath(os.path.normpath(path))))        # make absolute and handle symbolic links, split into components      sub_parts = _get_normalized_parts(potential_subdirectory)      parent_parts = _get_normalized_parts(expected_parent_directory)        if len(parent_parts) > len(sub_parts):          # a parent directory never has more path segments than its child          return False        # we expect the zip to end with the short path, which we know to be the parent      return all(part1==part2 for part1, part2 in zip(sub_parts, parent_parts))  

Answer by jgoeders for How to check whether a directory is a sub directory of another directory


def is_subdir(path, directory):      path = os.path.realpath(path)      directory = os.path.realpath(directory)      relative = os.path.relpath(path, directory)      return not relative.startswith(os.pardir + os.sep)  

Answer by Evgeni Sergeev for How to check whether a directory is a sub directory of another directory


Based on another answer here, with correction, and with a user-friendlier name:

def isA_subdirOfB_orAisB(A, B):      """It is assumed that A is a directory."""      relative = os.path.relpath(os.path.realpath(A),                                  os.path.realpath(B))      return not (relative == os.pardir              or  relative.startswith(os.pardir + os.sep))  

Answer by jme for How to check whether a directory is a sub directory of another directory


Python 3's pathlib module makes this straightforward withs 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  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 71

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.