[解決済み] Pythonでファイルが存在しない場合のみ、安全にファイルを作成する
質問
ファイルがすでに存在するかどうかに基づいてファイルに書き込み、ファイルがまだ存在しない場合にのみ書き込むことを希望します (実際には、存在しないファイルを見つけるまでファイルを試し続けたいのです)。
で提案されているように、次のコードは潜在的な攻撃者がシンボリックリンクを挿入する方法を示しています。 この投稿 で提案されているように、ファイルに対するテストと書き込まれるファイルの間にシンボリックリンクを挿入する方法を示しています。コードが十分に高い権限で実行される場合、これは任意のファイルを上書きすることができます。
この問題を解決する方法はあるのでしょうか?
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')
どのように解決するのですか?
編集
: こちらもご覧ください
デイブ・ジョーンズの回答
: Python 3.3 以降は
x
フラグを
open()
を追加することで、この機能を提供することができます。
以下、回答原文
はい、しかしPythonの標準的な
open()
の呼び出しを使うことはできません。を使う必要があります。
os.open()
これは、基礎となる C コードにフラグを指定することができます。
特に、あなたが使いたいのは
O_CREAT | O_EXCL
. の man ページから
open(2)
の下にある
O_EXCL
を私の Unix システム上で実行します。
この呼び出しがファイルを作成することを確認します: このフラグが
O_CREAT
と共に指定され、パス名が既に存在する場合はopen()
は失敗します。 の動作はO_EXCL
の動作は未定義です。O_CREAT
が指定されていない場合は未定義です。これら二つのフラグが指定された場合、シンボリックリンクは追跡されない: パス名がシンボリックリンクの場合
open()
は、シンボリックリンクがどこを指しているかに関わらず、失敗します。
O_EXCL
は、カーネル 2.6 以降で NFSv3 以降を使用している場合のみ、NFS でサポートされます。 NFS がサポートされている環境ではO_EXCL
がサポートされていない環境では、ロックタスクを実行するためにこれに依存するプログラムにはレースコンディションが含まれます。
というわけで、完璧ではありませんが、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!")
関連
-
[解決済み】pip install mysql-python は EnvironmentError: mysql_config not found で失敗します。
-
[解決済み] Pythonでリストをファイルに書き込む
-
[解決済み] Python の open() はファイルが存在しない場合、ファイルを作成しない
-
[解決済み] Pythonで一定の大きさの空リストを作成する
-
[解決済み] 複数のPythonバージョンとPIPに対応する?
-
[解決済み] なぜpythonはforやwhileループの後に'else'を使うのですか?
-
[解決済み] 存在しないかもしれないファイルを削除するための最もpythonicな方法
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み] [Solved] .whlファイル付きのPythonパッケージをインストールする方法は?
-
[解決済み] Alembicアップグレードスクリプトでインサートやアップデートを実行するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】ファイルが存在するかどうかをチェックするPythonicな方法?重複
-
[解決済み] Pythonのマルチプロセッシングプールimap_unorderedの呼び出しの進捗を表示しますか?
-
[解決済み] Jupyterノートブックでenv変数を設定する方法
-
[解決済み] pandasのDataFrameから空のセルを含む行を削除する
-
[解決済み] バブルソートの宿題
-
[解決済み] Pythonのインスタンス変数とクラス変数
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] Pythonで、ウェブサイトが404か200かを確認するためにurllibをどのように使用しますか?
-
[解決済み] if 節の終了方法
-
[解決済み] Pythonでランダムなファイル名を生成する最良の方法