【问题标题】:How to join with relative paths only?如何仅加入相对路径?
【发布时间】:2014-07-01 12:28:48
【问题描述】:

对于一个简单的 Web 服务器脚本,我编写了以下函数,将 url 解析为文件系统。

def resolve(url):
    url = url.lstrip('/')
    path = os.path.abspath(os.path.join(os.path.dirname(__file__), url))
    return path 

以下是 __file__ 变量为 C:\projects\resolve.py 的一些示例输出。

/index.html    => C:\projects\index.html
/\index.html   => C:\index.html
/C:\index.html => C:\index.html

第一个例子很好。 url 被解析为脚本目录中的一个文件。但是,我没想到第二个和第三个例子。由于附加的路径被解释为绝对路径,它完全忽略了脚本文件所在的目录。

这是一个安全风险,因为可以访问文件系统上的所有文件,而不仅仅是脚本子目录中的文件。为什么 Python 的 os.path.join 允许加入绝对路径,我该如何防止呢?

【问题讨论】:

    标签: python python-3.x path filesystems webserver


    【解决方案1】:

    os.path.join()不适合不安全输入,不行。绝对路径忽略它之前的参数是完全故意的;这允许在配置文件中同时支持绝对路径和相对路径,例如,无需测试输入的路径。只需使用os.path.join(standard_location, config_path),它就会为您做正确的事情。

    看看Flask's safe_join() 处理不受信任的文件名:

    import posixpath
    import os.path
    
    _os_alt_seps = list(sep for sep in [os.path.sep, os.path.altsep]
                        if sep not in (None, '/'))
    
    def safe_join(directory, filename):
        # docstring omitted for brevity
        filename = posixpath.normpath(filename)
        for sep in _os_alt_seps:
            if sep in filename:
                raise NotFound()
        if os.path.isabs(filename) or \
           filename == '..' or \
           filename.startswith('../'):
            raise NotFound()
        return os.path.join(directory, filename)
    

    这首先使用posixpath(与平台无关的os.path 模块的POSIX 实现)来规范化URL 路径;这将删除任何嵌入的 .././ 路径段,使其成为完全规范化的相对或绝对路径。

    然后排除/ 以外的任何替代分隔符;例如,您不能使用/\index.html。最后但同样重要的是,绝对文件名或相对文件名也被明确禁止。

    【讨论】:

      猜你喜欢
      • 2016-05-01
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 2014-03-16
      • 1970-01-01
      • 2015-01-07
      • 2015-09-13
      相关资源
      最近更新 更多