100

そのファイルが既に存在するかどうかに基づいてファイルに書き込みたいのですが、まだ存在しない場合にのみ書き込みます (実際には、存在しないファイルが見つかるまでファイルを試し続けたいと思います)。

次のコードは、この投稿で提案されているように、ファイルと書き込まれているファイルのテストの間に、潜在的な攻撃者がシンボリック リンクを挿入する方法を示しています。コードが十分に高い権限で実行されると、任意のファイルが上書きされる可能性があります。

この問題を解決する方法はありますか?

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')
4

3 に答える 3

97

編集: Dave Jonesの回答も参照してください:Python 3.3から、xフラグを使用しopen()てこの機能を提供できます。

以下の元の回答

はい。ただし、Python の標準open()呼び出しは使用しません。代わりに使用する必要がありますos.open()。これにより、基になる C コードにフラグを指定できます。

特に、使用したいO_CREAT | O_EXCL. 私のUnixシステムのopen(2)下のmanページから:O_EXCL

この呼び出しがファイルを作成することを確認してください。このフラグが と組み合わせて指定されO_CREAT、パス名が既に存在する場合、open()失敗します。が指定されていない場合の動作O_EXCLは未定義ですO_CREAT

これら 2 つのフラグが指定されている場合、シンボリック リンクはたどられません。パス名がシンボリック リンクopen()の場合、シンボリック リンクがどこを指しているかに関係なく失敗します。

O_EXCL カーネル 2.6 以降で NFSv3 以降を使用している場合、NFS でのみサポートされます。NFSO_EXCLサポートが提供されていない環境では、ロック タスクを実行するために NFS に依存するプログラムには競合状態が含まれます。

完璧ではありませんが、知る限り、この競合状態を回避するのに最も近い方法です。

編集: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!")
于 2012-06-11T11:53:15.560 に答える
79

参考までに、Python 3.3 では、このユースケースに対応するため'x'に関数に新しいモードが実装されています (作成のみ、ファイルが存在する場合は失敗)。モードは単独で指定されるopen()ことに注意してください。結果を aとして'x'使用するのは冗長です (呼び出しが成功した場合にできる唯一のことは、とにかくファイルに書き込むことです。呼び出しが成功した場合、ファイルは存在しませんでした)。'wx'ValueError'w'

>>> f1 = open('new_binary_file', 'xb')
>>> f2 = open('new_text_file', 'x')

Python 3.2 以下 (Python 2.x を含む) については、受け入れられた回答を参照してください。

于 2013-08-27T20:26:09.073 に答える
-1

このコードは、ファイルが存在しない場合でも簡単に作成できます。

import os
if not os.path.exists('file'):
    open('file', 'w').close() 
于 2013-03-14T04:19:22.660 に答える