I'm trying to check if a given user-supplied string is a simple file/folder name. I plan on using os.path.join() to concatenate this name to a preset root directory, but I want to detect and prohibit paths that try to traverse anywhere outside of that root directory.
For example, a string with the value 'track001.mp3' would be fine, it would resolve to 'root_dir/track001.mp3'. However, these should be detected and disallowed:
'../other_root_dir/'
'/etc'
'/'
'~'
'subdir/inner_file'
I would advise you to create the path string as you normally would assuming that the user is behaving (e.g. passing a "simple" or conforming path name). Then I'd use os.path.expandvars
and os.path.normpath
to get the actual path name. Finally, I'd check to make sure that the actual path name resides within the root directory. Something like:
from os.path import expandvars, normpath, join
ROOT_DIR = 'root_dir'
user_path = 'some_path'
test_path = normpath(expandvars(join(ROOT_DIR, user_path)))
expected_prefix = normpath(ROOT_DIR)
if not test_path.startswith(expected_prefix):
raise ValueError(f'Invalid path "{user_path}"') # python3.6 f-string.