安全地创build一个文件,当且仅当它不存在于python中
我希望根据文件是否已经存在写入文件,只有在文件不存在的情况下才写入文件(实际上,我希望不断尝试文件,直到find不存在的文件)。
下面的代码显示了一个潜在的攻击者可以插入一个符号链接的方式,正如在这篇文章中对文件和正在编写的文件的testing之间所build议的。 如果代码以足够高的权限运行,则可能会覆盖任意文件。
有什么办法可以解决这个问题吗?
import os import errno file_to_be_attacked = 'important_file' with open(file_to_be_attacked, 'w') as f: f.write('Some important content!\n') test_file = 'testfile' try: with open(test_file) as f: pass except IOError, e: # symlink created here os.symlink(file_to_be_attacked, test_file) if e.errno != errno.ENOENT: raise else: with open(test_file, 'w') as f: f.write('Hello, kthxbye!\n')
编辑 :另请参阅Dave Jones的答案 :从Python 3.3开始,可以使用x
标志来open()
来提供这个function。
下面的原始答案
是的,但不使用Python的标准open()
调用。 你需要使用os.open()
,它允许你指定底层C代码的标志。
尤其要使用O_CREAT | O_EXCL
O_CREAT | O_EXCL
。 从我的Unix系统上的O_EXCL
下open(2)
的手册页:
确保此调用创build文件:如果此标志与
O_CREAT
一起指定,且path名已存在,则open()
将失败。 如果没有指定O_CREAT
则O_EXCL
的行为是不确定的。如果指定了这两个标志,则不会遵循符号链接:如果path名是符号链接,则无论符号链接指向何处,
open()
都会失败。在内核2.6或更高版本上使用NFSv3或更高版本时,
O_EXCL
仅在NFS上受支持。 在没有提供NFSO_EXCL
支持的环境中,依赖它执行locking任务的程序将包含竞争条件。
所以这不是完美的,但AFAIK是最接近你可以避免这种竞争条件。
编辑:使用os.open()
而不是open()
的其他规则仍然适用。 特别是,如果要使用返回的文件描述符进行读取或写入,则还需要使用O_RDONLY
, O_WRONLY
或O_RDWR
标志之一。
所有的O_*
标志都在Python的os
模块中,所以你需要import os
并使用os.O_CREAT
等。
例:
import os import errno flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY try: file_handle = os.open('filename', flags) except OSError as e: if e.errno == errno.EEXIST: # Failed as the file already exists. pass else: # Something unexpected went wrong so reraise the exception. raise else: # No exception, so the file must have been created successfully. with os.fdopen(file_handle, 'w') as file_obj: # Using `os.fdopen` converts the handle to an object that acts like a # regular Python file object, and the `with` context manager means the # file will be automatically closed when we're done with it. file_obj.write("Look, ma, I'm writing to a new file!")
作为参考,Python 3.3在open()
函数中实现了一个新的'x'
模式来覆盖这个用例(只有创build,如果文件存在则失败)。 请注意, 'x'
模式是自行指定的。 使用'wx'
导致ValueError
因为'w'
是多余的(如果调用成功,则唯一可以做的事情是写入文件;如果调用成功则不能存在):
>>> f1 = open('new_binary_file', 'xb') >>> f2 = open('new_text_file', 'x')
对于Python 3.2及更低版本(包括Python 2.x),请参阅接受的答案 。
这个代码将很容易创build一个文件,如果一个不存在。
import os if not os.path.exists('file'): open('file', 'w').close()