应用程序想要解析并“执行”一个文件,并且出于安全原因想要断言该文件是可执行的。
片刻思考,你意识到这个初始代码有一个竞争条件,使得安全方案无效:
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
shell的事实
你下载的脚本,我考虑过上面问题中的设计。
也许最后,也许我们应该保持简单:如果文件必须是可执行文件,则使其可执行,并让内核在用户调用时执行它。将任务委派给它所属的地方。
答案 0 :(得分:3)
可执行性附加到您打开的文件,没有任何内容阻止多个文件指向包含您要读取的数据的inode。换句话说,相同的数据可以从同一文件系统中其他地方的非可执行文件中读取。此外,即使在打开文件后,您也无法阻止同一文件的可执行性发生变化,甚至可以取消链接。
我看到的“尽力而为”是在打开的文件上使用os.fstat
进行检查,并检查保护模式和修改时间之前和之后,但充其量只会降低可能性您在阅读文件时未检测到更改。
再想一想,如果你是这个文件中数据的原始创建者,你可以考虑编写一个从未与文件系统相关联的inode,这是通过文件共享内存的一种常用技术。或者,如果包含的数据最终必须公开给其他用户,则可以使用文件锁定,然后逐步将保护位扩展到需要它的用户。
最终,您必须确保恶意用户根本没有对该文件的写访问权。
答案 1 :(得分:2)
你无法完全解决这种竞争条件 - 例如,在您首次打开的版本中,然后检查权限,可能在您打开文件之后权限会被更改在您更改权限之前。
如果您可以将文件原子地移动到潜在的坏人无法到达的目录,那么您可以放心,在您处理文件时,不会对您的文件进行任何改变。如果潜在的坏人可以到达到处,或者你无法将文件移动到他们无法到达的地方,那就没有任何防御。
顺便说一句,我不清楚这个方案,即使它可以使用,也会增加任何安全性 - 当然,如果坏人可以在文件中放入有毒内容,那么它不会超出它们{{1它也是吗?答案 2 :(得分:0)
你能做的最好的事情是:
当然,有一些缺点,但如果你的用例就像你说的那么简单,它可以解决问题。
答案 3 :(得分:0)
您应该更改文件所有权,以便攻击者无法访问它“chown root:root file_name”。执行“chmod 700 file_name”,以便其他帐户无法读取/写入/执行该文件。这样可以避免TOCTOU的问题,这就是人们阻止文件被系统上拥有用户帐户的攻击者修改的方式。
答案 4 :(得分:0)
另一种方法是将文件名更改为意外的内容,甚至将整个文件(如果不是太大)复制到临时目录(必要时加密),进行检查,然后重命名/复制归档。
当然这是一个非常繁重的过程。
但是你最终还是因为系统从一开始就没有设置安全性。安全程序会签署或加密他想要保密的数据。在你的情况下,这是不可能的。
除非您真的需要进行大量加密,否则无法确保您无法控制的计算机上的100安全。