公開日:2007年9月26日
独立行政法人情報処理推進機構
セキュリティセンター
本ページの情報は2007年9月時点のものです。
記載の資料は資料公開当時のもので、現在は公開されていないものも含みます。
テンポラリファイルにデータを一時的に保持する際、重要な情報が含まれる場合は /tmp 等共通のディレクトリの使用を避けた方がよい。個人情報、暗号鍵、パスワード等は特にそうである。
/tmp 等のシステム共通のディレクトリはそのコンピュータのほとんどすべてのアカウントから読み書きできるため、情報が漏えいしやすい。また、シンボリックリンク攻撃を受けるおそれがある。
重要な情報を一時ファイルに書き込む処理のあるプログラムが対象となる。
テンポラリファイルとして格納したデータが漏えいしてしまう問題は、長期的に保管するデータでは無く、一時的に利用するだけという扱いにより、十分な注意が向けられないことから発生している。この対策としては、まず、テンポラリファイルに格納するデータに重要な情報(個人情報や暗号鍵、パスワード等)が含まれないようにすることであるが、重要な情報の格納が必要な場合には、次のような項目に注意する必要がある。
サービスを提供するデーモンプログラム等は、/tmp 等の共通のディレクトリを使用せずに、次のようにプログラム専用のテンポラリディレクトリを作成し、そこにテンポラリファイルを作成するようにする。
このようにすると、他のユーザからの干渉が避けられ、情報は漏洩しにくくなる。
以下の3つの関数は、現在でも使用できるが、脆弱性があるため使用を避ける。
その代わりに、以下に述べらている脆弱性が解消された mkstemp(3) 又は tmpfile(3) を使用するようにする。
mkstemp() 関数や tmpfile() 関数を使うことで,安全で適切なテンポラリファイルの作成が可能である。これらの関数は以下の3つの注意点をすべて網羅している。
mkstemp()関数はテンポラリファイルを作成,オープンし,ファイル記述子を返す。mkstemp()関数の引数には作成するテンポラリファイルのファイル名のテンプレートを渡す。テンプレートは
/tmp/my_tmp_file_XXXXXX
といった文字列で,文字列の最後は6つの「X」で終わる必要がある。この「XXXXXX」部分が自動的にランダムな文字列に置き換えられ,ランダムな名前のテンポラリファイルが作成される。テンプレートに
/mydaemon_dir/tmp/prefix_XXXXXX
といった文字列を与えると,デーモン専用のテンポラリファイルディレクトリ「/mydaemon_dir/tmp/」にテンポラリファイルを作成することもできる。
[例 mkstemp() 使用]
char filepath[] = "/tmp/my_file_XXXXXX";
↑6 文字の'X'が必要
fd = mkstemp(filepath);
filepath には、 'XXXXXX'が変換されて "/tmp/my_file_PvQLMk" のような文字列が返される。
tmpfile()関数はmkstemp()関数を使いやすくした位置付けのものである。具体的には次のような動作をする。
テンポラリファイルのオープンは、本人のみが読み書きできるようにし、排他モードでオープンする。
テンポラリファイルを open() により作成するのであれば、次の例のようにパラメータを指定する。
fd = open(path, S_IRUSR | S_IWUSR, O_CREAT | O_RDWR | O_EXCL);
シンボリックリンク攻撃は、攻撃者が /tmp 等に読み書きするファイルを予測し、そのファイルが別なファイルを指すようにシンボリックリンクを張り、別なファイルにアクセスするように仕向けるものである。
シンボリックリンク攻撃の対策については、本コンテンツの別記事「シンボリックリンク攻撃対策」を参照されたい。
テンポラリファイルを作成し、使用し終わったらクローズ close() し、削除 unlink()するのが一般的だが、テンポラリファイルを別なプログラムで使用しないのであれば、次のようにするとより安全になる。
ファイルを作成 open() 直後に unlink() してしまう。unlink() してしもディレクトリから消えるのみで、ファイル自体にはアクセス可能であり、ファイル自体は存在し続けるが,どのディレクトリにも属さない状態となる。つまりファイル名が存在しなくなり、このファイルは二度と open() できなくなる。unlink() 以降はそのファイルへアクセスできるのは,unlink() 以前に open() したプロセスのみとなる。
このように open() の直後に unlink() されたファイルは、プロセスが異常終了した時には、既に unlink(2) されているので残骸が残ることもなくなる。具体的には下記の例のようにする。
[例]
#define TMPFILE "/tmp/my_tmp_file"
fd = open(TMPFILE, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
if(fd==-1) exit(1);
unlink(TMPFILE);
..... fd を使用して write() 等を行う。
過去のUnixシステムでは、所有者が root の /tmp のファイルを一般ユーザが削除できてしまっていた。現在のUnixシステムでは、ディレクトリの属性にスティッキービットを on にすることで、この問題を解決している。
drwxrwxrwt 5 root root 4096 Dec 5 04:24 /tmp
↑
t:スティッキービット
このビットが立っていると、以下のいずれかの条件に合致しないと、そのディレクトリ以下にあるファイルの削除権限が与えられない。
Windowsの場合、mkstemp() のような関数は Win32 APIには存在しない。Win32 API の GetTempPath() 関数により、テンポラリファイルのディレクトリを取得できるが、ランダムなファイル名を作成する APIは用意されていない。このため信頼性のある乱数等を使用して、ファイル名を作成する必要がある。
(注釈)GetTempFileName() という関数があるが、これはファイル名の一意性を保障するのみで、推測困難なランダムなファイル名を作成するわけではない。