代码之家  ›  专栏  ›  技术社区  ›  u0b34a0f6ae

在python中声明文件权限时避免争用条件

  •  1
  • u0b34a0f6ae  · 技术社区  · 15 年前

    应用程序希望解析并“执行”一个文件,并且为了安全起见,希望断言该文件是可执行的。

    稍作思考,您就会意识到这个初始代码有一个使安全方案无效的竞争条件:

    import os
    
    class ExecutionError (Exception):
        pass
    
    def execute_file(filepath):
        """Execute serialized command inside @filepath
    
        The file must be executable (comparable to a shell script)
        >>> execute_file(__file__)  # doctest: +ELLIPSIS
        Traceback (most recent call last):
            ...
        ExecutionError: ... (not executable)
        """
        if not os.path.exists(filepath):
            raise IOError('"%s" does not exist' % (filepath, ))
        if not os.access(filepath, os.X_OK):
            raise ExecutionError('No permission to run "%s" (not executable)' %
                    filepath)
    
        data = open(filepath).read()
    
        print '"Dummy execute"'
        print data
    

    竞争条件存在于

    os.access(filepath, os.X_OK)
    

    data = open(filepath).read()
    

    因为在这两个系统调用之间,文件可能被具有不同内容的不可执行文件覆盖。

    我拥有的第一个解决方案是更改关键调用的顺序(并跳过现在的冗余存在检查):

    fobj = open(filepath, "rb")
    if not os.access(filepath, os.X_OK):
        raise ExecutionError('No permission to run "%s" (not executable)' %
                filepath)
    
    data = fobj.read()
    

    这能解决比赛条件吗?我怎样才能正确地解决它?

    安全方案的基本原理(我想)

    该文件将能够在其内部执行任意命令。 环境,因此可以与shell脚本进行比较。

    在带有.desktop文件的免费桌面上有一个安全漏洞 应用程序:该文件可以使用参数指定任何可执行文件,以及 它可以选择自己的图标和名称。所以随机下载的文件可以隐藏 在任何名字或图标后面,做任何事情。那太糟糕了。

    这是通过要求.desktop文件具有可执行位来解决的。 设置,否则将不使用名称/图标和自由桌面呈现它们 将在开始前询问用户是否要启动程序。

    与MacOSX的设计相比:“这个程序是从网上下载的, 你确定要打开它吗?”.

    所以在寓言中,你必须 chmod +x 壳 你下载的脚本,我在上面的问题中考虑了设计。

    结束语

    最后,也许我们应该保持简单:如果文件必须是可执行的,那么让它成为可执行的,并让内核在用户调用时执行它。将任务委派到它所属的位置。

    5 回复  |  直到 15 年前
        1
  •  3
  •   Matt Joiner    15 年前

    可执行性附加到您打开的文件上,没有什么阻止几个文件指向包含您要读取的数据的inode。换句话说,相同的数据可以从同一文件系统中其他地方的不可执行文件中读取。此外,即使在打开文件之后,也不能阻止同一文件的可执行性发生更改,甚至可以取消链接。

    正如我所看到的,你能得到的“最大努力”是用 os.fstat 在打开的文件上,检查之前和之后的保护模式和修改时间,但这最多只能减少在读取文件时无法检测到更改的可能性。

    再想一想,如果您是这个文件中数据的原始创建者,您可以考虑首先编写一个从未链接到文件系统的inode,这是通过文件共享内存的一种常见技术。或者,如果所包含的数据最终必须公开给其他用户,则可以使用文件锁定,然后逐步将保护位扩展到需要它的用户。

    最终,您必须确保恶意用户对该文件没有写访问权。

        2
  •  2
  •   Alex Martelli    15 年前

    您不能完全解决这个争用条件——例如,在您首先打开然后检查权限的版本中,它是 可能的 权限在您打开文件之后和更改权限之前更改。

    如果你能自动地将文件移动到一个潜在坏人无法到达的目录,那么你就可以放心,当你处理文件时,文件的任何内容都不会从你的鼻子下面改变。如果潜在的坏人能接触到 到处 或者你不能把文件移到他们找不到的地方,就没有防御。

    顺便说一句,我不清楚这个方案,即使它可以工作,实际上会增加任何安全性——当然,如果坏人可以把有毒的内容放在文件中,它不会超出他们的范围。 chmod +x 也是吗?

        3
  •  0
  •   Bite code    15 年前

    你能做的最好的是:

    • 保存权限。
    • 将其更改为您自己的唯一用户(具有程序名称的内容),并禁止其他人运行它。
    • 检查(如果需要,在保存的权限上)。
    • 运行您的进程。
    • 将权限设置回已保存的权限。

    当然,也有缺点,但是如果您的用例像您所说的那样简单,它就可以做到这一点。

        4
  •  0
  •   rook    15 年前

    您应该更改文件的所有权,这样攻击者就不能访问它“chown-root:root-file_-name”。执行“chmod 700文件名”,这样其他帐户就无法读取/写入/执行该文件。这就避免了toctou的问题,这就是人们如何防止在您的系统上拥有用户帐户的攻击者修改文件。

        5
  •  0
  •   Bite code    15 年前

    另一种方法是将文件名更改为意外的名称,或者甚至将整个文件(如果文件不太大)复制到临时目录(必要时加密),进行检查,然后重命名/复制文件。

    当然,这是一个非常沉重的过程。

    但你最终会这样做,因为从一开始就没有为安全设置系统。一个安全的程序会签署或加密他想要保持安全的数据。在你的情况下,这是不可能的。

    除非你真的需要大量加密,否则在你无法控制的机器上,没有办法确保100的安全。