是否足以在文件路径中测试'/../'以防止转义子目录?

时间:2012-12-09 10:21:51

标签: python web

我在python中有一些代码检查文件路径是否访问子目录中的文件。 Web服务器可以访问静态文件夹中的文件。

我使用以下代码段:

path = 'static/' + path
try:
    if '/../' in path:
        raise RuntimeError('/../ in static file path')
    f = open(path)
except (RuntimeError, IOError):
    app.abort(404)
    return

如果路径干净就足够了。

有没有办法编写一个访问父目录的路径,而这个目录不会被这个简单的测试检测到?

3 个答案:

答案 0 :(得分:2)

我建议使用os.path.relpath,它需要一条路径并从给定目录中找出最简洁的相对路径。这样,您只需要测试路径是否以".."

开头

例如

path = ...
relativePath = os.path.relpath(path)
if relativePath.startswith(".."):
    raise RuntimeError("path escapes static directory")
completePath = "static/" + relativePath

如果您需要担心sym链接,您还可以使用os.readlink将实际路径替换为符号链接。

答案 1 :(得分:1)

Flask有一些辅助函数,我认为你可以毫无问题地复制到你的代码中。推荐的语法是:

filename = secure_filename(dirty_filename)
path = os.path.join(upload_folder, filename)

Werkzeug实现secure_filename并使用此代码清理文件名:

_filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]')    
_windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1',
                         'LPT2', 'LPT3', 'PRN', 'NUL')

def secure_filename(filename):
    r"""Pass it a filename and it will return a secure version of it.  This
    filename can then safely be stored on a regular file system and passed
    to :func:`os.path.join`.  The filename returned is an ASCII only string
    for maximum portability.

    On windows system the function also makes sure that the file is not
    named after one of the special device files.

    >>> secure_filename("My cool movie.mov")
    'My_cool_movie.mov'
    >>> secure_filename("../../../etc/passwd")
    'etc_passwd'
    >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
    'i_contain_cool_umlauts.txt'

    The function might return an empty filename.  It's your responsibility
    to ensure that the filename is unique and that you generate random
    filename if the function returned an empty one.

    .. versionadded:: 0.5

    :param filename: the filename to secure
    """
    if isinstance(filename, unicode):
        from unicodedata import normalize
        filename = normalize('NFKD', filename).encode('ascii', 'ignore')
    for sep in os.path.sep, os.path.altsep:
        if sep:
            filename = filename.replace(sep, ' ')
    filename = str(_filename_ascii_strip_re.sub('', '_'.join(
                   filename.split()))).strip('._')

    # on nt a couple of special files are present in each folder.  We
    # have to ensure that the target file is not such a filename.  In
    # this case we prepend an underline
    if os.name == 'nt' and filename and \
       filename.split('.')[0].upper() in _windows_device_files:
        filename = '_' + filename

    return filename

答案 2 :(得分:0)

..//

这基本上是相同的,但是因为你直接匹配/../的字符串 我添加的一个将不会被检测到并将获得父目录。