C または C++ を使用して、ファイルを復号化してディスクに保存した後、アプリケーションがクラッシュしたり、システムの電源がオフになったりして適切にクリーンアップできない場合に、ファイルが確実に削除されるようにするにはどうすればよいですか? Windows および Linux で C または C++ を使用していますか?
13 に答える
残念ながら、システム全体がクラッシュした場合にファイルが確実に削除されるようにする 100% 確実な方法はありません。ファイルがディスク上にあるときにユーザーがプラグを抜いた場合にどうなるかを考えてみてください。いくら例外を処理しても、その (最悪の) ケースからあなたを守ることはできません。
あなたができる最善のことは、最初から復号化されたファイルをディスクに書き込まないことです。ファイルが暗号化された形式と復号化された形式の両方で存在する場合、それはセキュリティ上の弱点です。
次善の策は、構造化された例外処理に関する Brian の提案を使用して、一時ファイルが確実にクリーンアップされるようにすることです。これはすべての可能性からあなたを守るわけではありませんが、大いに役立ちます。
最後に、アプリケーションの起動時に復号化された一時ファイルを確認することをお勧めします。これにより、システムが完全にクラッシュした場合にアプリケーションをクリーンアップできます。これらのファイルを常に手元に置いておくのは理想的ではありませんが、少なくともこれにより、できるだけ早くそれらを取り除くことができます。
復号化されたファイルをディスクにまったく書き込まないでください。
システムの電源が切られていても、ファイルはまだディスク上にあるため、ディスクにアクセスできるため、ファイルにアクセスできます。
暗号化されたファイル システムの使用は例外ですが、これはプログラムの制御範囲外です。
それを完全に避けるようにしてください:
ファイルが機密性の高いものである場合、最善の策は、最初から復号化された形式でディスクに書き込まないことです。
クラッシュからの保護: 構造化された例外処理:
ただし、構造化された例外処理を追加して、クラッシュをキャッチできます。
彼らがプラグを抜いたらどうしますか?:
これを防ぐ方法はあります...
Windows を使用している場合は、MoveFileEx とオプション MOVEFILE_DELAY_UNTIL_REBOOT を宛先を NULL で使用して、次回の起動時にファイルを削除できます。これにより、ファイルが削除されていないため、コンピューターの偶発的なシャットダウンを防ぐことができます。また、このファイルへのハンドルを排他的に開いていることを確認することもできます (FILE_SHARE_READ などの共有権限を指定せず、CreateFile を使用してファイルを開きます)。そうすれば、誰もそれを読むことができなくなります。
問題を回避するその他の方法: これらはすべて、ディスク上に復号化されたファイルを保持するための言い訳にはなりませんが、
\\?\ のファイル構文を使用して、MAX_PATH より大きいファイルに書き込むことも検討できます。これにより、Windows エクスプローラーでファイルを参照できなくなります。
一時属性を持つようにファイルを設定する必要があります
ファイルに隠し属性を設定する必要があります
これが Windows で機能するかどうかはわかりませんが、Linux では、復号化されたファイルにアクセスするために必要なプロセスが 1 つだけであると仮定すると、ファイルを開き、unlink() を呼び出してファイルを削除できます。プロセスがファイルを開いたままにしておく限り、ファイルは存在し続けますが、ファイルを閉じるかプロセスが停止すると、ファイルにアクセスできなくなります。
もちろん、ファイルの内容はまだディスク上にあるため、実際にはファイルを削除するだけではなく、内容をゼロにする必要があります。復号化されたファイルをディスク上に置く必要がある理由はありますか (サイズ?)。復号化されたバージョンをメモリに保持し、できればスワップ不可としてマークして、ディスクにヒットしないようにすることをお勧めします。
C では (C++ でも同様だと思います)、プログラムがクラッシュしない限り、atexit()
ハンドラーを登録してクリーンアップを行うことができます。_exit()
orはハンドラー_Exit()
をバイパスするため、使用しないでください。atexit()
ただし、他の人が指摘したように、復号化されたデータがディスクに書き込まれないようにすることをお勧めします。また、単に使用するunlink()
(または同等のものを使用する) だけでは不十分です。元のデータの上に他のデータを書き直す必要があります。ジャーナリングされたファイル システムでは、これが非常に困難になります。
ファイルの削除に問題があります。それは本当になくなっていません。ハードドライブからファイルを削除しても(ごみ箱は数えません)、ファイルは実際には消えていません。ファイルへのポインタだけが削除されます。
彼らがハードドライブを6、8、24回上書きするそれらのスパイ映画を見たことがあります、そしてそれは彼らがそれがきれいであることを知る方法です..まあ彼らは理由のためにそれをします。ファイルの復号化されたデータを保存しないようにあらゆる努力をします。または、必要に応じて、少量のデータにします。でも、ばらばらのデータ。
あなたがしなければならないなら、彼らはキャッチを試みてあなたを少し保護するはずです..しかし、停電から保護することはできません。
幸運を祈ります。
C ++では、RAII戦術を使用する必要があります。
class Clean_Up_File {
std::string filename_;
public Clean_Up_File(std::string filename) { ... } //open/create file
public ~Clean_Up_File() { ... } //delete file
}
int main()
{
Clean_Up_File file_will_be_deleted_on_program_exit("my_file.txt");
}
RAIIは、多くのクリーンアップを自動化するのに役立ちます。スタック上にオブジェクトを作成するだけで、そのオブジェクトはその存続期間の終わりにクリーンアップされます(オブジェクトがスコープから外れたときに呼び出されるデストラクタで)。 ScopeGuardはそれを少しでも簡単にします。
しかし、他の人が述べているように、これは「通常の」状況でのみ機能します。ユーザーがコンピューターのプラグを抜いた場合、ファイルが削除されることを保証することはできません。また、ファイルの削除を取り消すことができる場合があります(UNIXでも、「ハードドライブをgrepする」ことができます)。
また、コメントで指摘されているように、オブジェクトがスコープから外れない場合(たとえば、std::exit(int)
関数が現在のスコープを離れずにプログラムを終了する場合)、RAIIが機能しない場合があります。個人的には、を呼び出すことはありませんstd::exit(int)
。代わりに、例外をスローするか(スタックを巻き戻してデストラクタを呼び出します。これは「異常な終了」と見なします)、エラーコードを返しますmain()
(デストラクタを呼び出します。これも「異常な」と見なします)。出口")。IIRC、送信SIGKILL
もデストラクタを呼び出さSIGKILL
ず、捕まえられないので、あなたも運が悪いです。
プロセスは、それ自体を保護または監視することはできません。唯一の可能性は、復号化する他のプロセスの状態を定期的にチェックする一種のウォッチドッグとして 2 番目のプロセスを起動することです。他のプロセスがクラッシュした場合、ウォッチドッグはファイル自体を認識して削除します。
これは、ハースビート (他のプロセスがまだ生きているかどうかを確認するための他のプロセスの定期的なポーリング) を使用するか、他のプロセス自体から送信された割り込みを使用して行うことができます。これにより、クラッシュした場合にタイムアウトがトリガーされます。
たとえば、ソケットを使用して、ウォッチドッグとアプリ間の接続を機能させることができます。
ページファイル / スワップ パーティションへのスワップを防ぐために、何らかのロック メカニズムが必要であることが明らかになりつつあります。Posix システムでは、これはm(un)lock* family of functions
.
tmpfile() を確認してください。
これは BSD UNIX の一部ですが、標準かどうかは不明です。
ただし、一時ファイルを作成し、自動的にリンクを解除して、閉じるときに削除されるようにします。
ファイル システムへの書き込みは (一時的であっても) 安全ではありません。
本当に必要な場合にのみ実行してください。
必要に応じて、メモリ内ファイル システムを作成できます。
自分で使用したことがないため、推奨事項はありませんが、簡単なグーグルでいくつか見つかりました.
コンピュータの電源はいつでも切れる可能性があることに注意してください。次に、気に入らない誰かが Linux のライブ CD を使って起動し、何も変更せずに、必要な詳細レベルでディスクを調べることができます。プレーンテキストをディスクに書き込むシステムは、このような攻撃に対して安全ではありませんし、実行するのも難しくありません。
ファイルを1と0で繰り返し上書きし、できればランダム性を注入する関数を設定し、プログラムの最後または終了時に実行するように設定できます。これは、ハードウェアまたはソフトウェアの不具合、電源障害、またはその他の中断がなく、ファイル システムが使用していると主張するセクターのみに書き込みを行う場合に機能します (たとえば、ジャーナリング ファイル システムでは、ファイルの一部が別の場所に残る可能性があります)。 )。
したがって、セキュリティが必要な場合は、平文が書き出されていないことを確認する必要があります。これは、スワップ領域または同等のものに書き込めないことも意味します。あなたが書いているすべてのプラットフォームでメモリをスワップ不可としてマークする方法を見つけてください。復号化キーなどは平文と同じように扱われることを確認してください。どのような状況でも決してディスクに書き込まれることはなく、スワップ不可能なメモリに保持されます。
次に、システムは、敵対者の侵入、妨害、および電源を切る前に RAM チップをフリーズすることを除いて、攻撃に対して安全である必要があります。または、当局が合法的に (ここで現地の法律を確認してください)、または違法にキーを要求します。
話の教訓: 本当のセキュリティは難しい。
私が実装しようとしている方法は、復号化をストリーミングすることです。これにより、メモリ内にある唯一の部分は、データが使用されているときに読み取り中に復号化される部分になります。パイプラインの図を次に示します。
これはストリーミング実装になるため、メモリ内にある唯一のデータは、特定の時点でアプリケーションで使用しているデータです。多くの従来のファイル トリックが利用できなくなったことを考えると、これはいくつかの注意を必要としますが、実装はストリーム ベースであるため、暗号化ストリームに変換されて復号化されるファイルのさまざまなポイントを探すことができます。異なるセクション。
基本的に、一度にファイルのブロックを暗号化します。そのため、特定のポイントをシークしようとすると、そのブロックが解読されて読み取られます。過去のブロックを読み取ると、次のブロックが復号化され、前のブロックが解放されます (crypt ストリーム内)。
この実装では、ファイルやメモリに復号化する必要はなく、他のストリーム コンシューマーおよびプロバイダー (fstream) と互換性があります。
これが私の「計画」です。私はこれまで fstream でこの種の作業を行ったことがありません。これに取り組む準備ができ次第、質問を投稿する予定です。
他のすべての回答に感謝します-それは非常に有益でした。
これはトリッキーなトピックです。通常、回避できる場合は、復号化されたファイルをディスクに書き込みたくありません。ただし、それらをメモリに保持しても、ページファイルなどの一部としてディスクに書き込まれないことが常に保証されるわけではありません。
私はずっと前にこれに関する記事を読みましたが、メモリページがディスクに書き込まれないことを保証できるものとできないという点で、Windows と Linux にはいくつかの違いがあることを覚えています。が、はっきりとは覚えていません。
デューデリジェンスを行いたい場合は、そのトピックを調べて読むことができます. それはすべて、脅威モデルと何を防御したいかによって異なります。結局のところ、圧縮空気を使用して RAM を冷却し、そこから暗号化キーを引き出すことができます (これは、実際にはクリスチャン スレーターの新しいスパイ番組、My Own Worst Enemy にありました。これは、最先端の正確なコンピューターの最適な使用法だと思いました。メディアのセキュリティ技術はまだ)
Linux/Unix では、ファイルを作成したらすぐに unlink を使用してください。プログラムがファイル記述子を閉じるか終了するとすぐに、ファイルは削除されます。
さらに良いことに、システム全体がクラッシュした場合でも、ファイルは削除されます。基本的に、リンクを解除するとすぐに削除されるためです。
もちろん、データはディスクから物理的に削除されるわけではないため、ハッキングできる可能性があります。