1

应用程序想要解析和“执行”一个文件,并且出于安全原因想要断言该文件是可执行的。

片刻思考,你意识到这个初始代码有一个竞争条件,使安全方案无效:

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 文件设置可执行位来解决,否则它们将不会以名称/图标呈现,并且免费桌面会询问用户是否要在开始之前启动程序。

对比一下 Mac OS X 的非常好的设计:“这个程序已经从网上下载了,你确定要打开它吗?”。

因此,在这个寓言中,以及您必须对下载的脚本进行外壳处理这一事实chmod +x,我考虑了上述问题中的设计。

结束语

也许总而言之,也许我们应该保持简单:如果文件必须是可执行的,则使其可执行并让内核在用户调用时执行它。将任务委托给它所属的地方。

4

5 回答 5

3

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

正如我所见,您可以使用的“最大努力”是os.fstat对打开的文件进行检查,并检查保护模式和修改前后的时间,但充其量只会减少在您阅读时未检测到更改的可能性文件。

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

最终,您必须确保恶意用户根本没有对该文件的写入权限。

于 2010-02-13T17:11:21.750 回答
2

您无法完全解决这种竞争条件——例如,在您第一次打开然后检查权限的版本中,权限可能会在您打开文件之后以及在您更改权限之前发生更改。

如果您可以将文件自动移动到潜在的坏人无法访问的目录,那么您可以放心,在您处理它时,不会从您的眼皮底下改变任何有关文件的内容。如果潜在的坏人可以到达任何地方,或者您无法将文件移动到他们无法到达的地方,那么就没有防御。

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

于 2010-02-13T16:56:08.170 回答
0

你能做的最好的事情是:

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

当然,也有缺点,但如果你的用例像你说的那么简单,它就可以解决问题。

于 2010-02-13T17:18:18.553 回答
0

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

于 2010-02-13T19:52:22.953 回答
0

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

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

But you end up with that because the system has not been set for safety from the beginning. A safe program would sign or encrypt data he wants to keep safe. In your case, it's not possible.

Unless you realy on heavy encrypting, there is not way to ensure 100 safety on a machine you don't control.

于 2010-02-16T14:00:23.010 回答