在python中清理文件路径

时间:2012-12-18 18:22:49

标签: python

我有一个文件浏览器应用程序,它将目录及其内容公开给用户。

我想清理用户输入,这是一个文件路径,因此它不允许绝对路径,如'/ tmp /'和相对路径,如'../../ etc'

是否有跨平台执行此操作的python函数?

6 个答案:

答案 0 :(得分:10)

对于那些寻找摆脱" A /./ B" - > " A / B和" A / B /../ C" - > " A / C"在路径中。 您可以使用os.path.normpath

答案 1 :(得分:4)

python

的综合文件路径清理程序

我对任何可用的消毒路径方法都不满意,所以我写了自己的,相对全面的路径消毒剂。这适用于从公共端点(http上传,REST端点等)获取输入,并确保如果将数据保存在生成​​的文件路径中,则不会损坏您的系统**。 (注意:此代码针对Python 3+,您可能需要进行一些更改才能使其在2.x上运行)

* 不保证!如果没有彻底检查,请不要依赖此代码。

** 再一次,没有保证!您仍然可以做一些疯狂的事情,并将* nix系统上的根路径设置为/dev//bin/或类似的东西。不要那样做。 Windows上也存在一些可能导致损坏的边缘情况(例如设备文件名),您可以检查secure_filename的{​​{1}} werkzeug方法,以便在处理时有一个良好的开端如果你的目标是Windows,请使用这些。

如何运作

  • 您需要指定根路径,杀菌人员将确保返回的所有路径都在此根目录下。检查utils功能,了解执行此操作的位置。确保根路径的值来自您自己的配置,而不是来自用户的输入!
  • 有一个文件名sanitiser:
    • 将unicode转换为ASCII
    • 将路径分隔符转换为下划线
    • 仅允许文件名中白名单中的某些字符。白名单包括所有小写和大写字母,所有数字,连字符,下划线,空格,开始和结束圆括号以及句号(句号)。如果您愿意,可以自定义此白名单。
    • 确保所有名称至少包含一个字母或数字(以避免使用'..'等名称)
  • 要获得有效的文件路径,您应该致电get_root_path。您可以选择在make_valid_file_path参数中传递子目录路径。这是根路径下面的路径,可以来自用户输入。您可以选择在path参数中传递文件名,这也可以来自用户输入。您传递的文件名中的任何路径信息都不会用于确定文件的路径,而是将其展平为文件名的有效安全组件。
    • 如果没有路径或文件名,它将返回正确格式化为主机文件系统的根路径,并带有尾随路径分隔符(/)。
    • 如果有子目录路径,它会将其拆分为组件部分,使用文件名sanitiser清理每个部分,并重建路径而不使用前导路径分隔符。
    • 如果有文件名,它将使用杀菌剂清理名称。
    • 它将filename路径组件以获取文件的最终路径。
    • 最后仔细检查生成的路径是否有效且安全,它会检查生成的路径是否位于根路径下的某个位置。通过拆分和比较路径的组成部分来正确完成此检查,而不是仅仅确保一个字符串从另一个字符串开始。

好的,有足够的警告和描述,这是代码:

os.path.join

答案 2 :(得分:0)

这将阻止用户输入诸如../../../../etc/shadow之类的文件名,但也将不允许文件位于basedir以下的子目录中:

from pathlib import Path
test_path = (Path(basedir) / user_input).resolve()
if test_path.parent != Path(basedir).resolve():
    raise Exception(f"Filename {test_path} is not in {Path(basedir)} directory")

如果要允许basedir下的子目录:

if not Path(basedir).resolve() in test_path.resolve().parents:
    raise Exception(f"Filename {test_path} is not in {Path(basedir)} directory")

答案 3 :(得分:0)

我最终在这里寻找一种处理我的用例的最终方法,并最终编写了自己的用例。我需要的是采取一种方法,将其强制纳入CWD。这是针对正在处理已挂载文件的CI系统的。

import java.util.*;

public class Test {

    static Scanner input = new Scanner(System.in);
    static double y;

    public static void main(String[] args) {
        double x = someMethod(5);
    }

    private static double someMethod(int nr) {
        try {
            y = input.nextDouble();
        } catch (InputMismatchException e) {System.out.println("Type in a double");}
        return y + nr;
    }
}

就我而言,我不想引发异常。我只想强迫给定的任何路径都将成为CWD中的绝对路径。

测试:

def relative_path(the_path: str) -> str:
    '''
    Force the spec path to be relative to the CI workspace
    Sandboxes the path so that you can't escape out of CWD
    '''
    # Make the path absolute
    the_path = os.path.abspath(the_path)
    # If it started with a . it'll now be /${PWD}/
    # We'll get the path relative to cwd
    if the_path.startswith(os.getcwd()):
        the_path = '{}{}'.format(os.sep, os.path.relpath(the_path))
    # Prepend the path with . and it'll now be ./the/path
    the_path = '.{}'.format(the_path)
    return the_path

答案 4 :(得分:0)

这是对@mneil 解决方案的改进,使用了relpath 的秘密第二个参数:

import os.path

def sanitize_path(path):
    """
    Sanitize a path against directory traversals

    >>> sanitize_path('../test')
    'test'
    >>> sanitize_path('../../test')
    'test'
    >>> sanitize_path('../../abc/../test')
    'test'
    >>> sanitize_path('../../abc/../test/fixtures')
    'test/fixtures'
    >>> sanitize_path('../../abc/../.test/fixtures')
    '.test/fixtures'
    >>> sanitize_path('/test/foo')
    'test/foo'
    >>> sanitize_path('./test/bar')
    'test/bar'
    >>> sanitize_path('.test/baz')
    '.test/baz'
    >>> sanitize_path('qux')
    'qux'
    """
    # - pretending to chroot to the current directory
    # - cancelling all redundant paths (/.. = /)
    # - making the path relative
    return os.path.relpath(os.path.normpath(os.path.join("/", path)), "/")

if __name__ == '__main__':
    import doctest
    doctest.testmod()

答案 5 :(得分:-1)

也许不仅仅是清理路径(黑名单),您只能允许(白名单)有效路径。

python在os.path中提供了各种工具,以独立的方式执行此操作