セキュリティセンターTOP > セキュアプログラミング講座 > C/C++言語編 > データ漏えい対策 > テンポラリファイル(Unix の一時ファイル)

第7章 データ漏えい対策
テンポラリファイル(Unix の一時ファイル)

テンポラリファイルにデータを一時的に保持する際、重要な情報が含まれる場合は /tmp 等共通のディレクトリの使用を避けた方がよい。個人情報、暗号鍵、パスワード等は特にそうである。

/tmp 等のシステム共通のディレクトリはそのコンピュータのほとんどすべてのアカウントから読み書きできるため、情報が漏えいしやすい。また、シンボリックリンク攻撃を受けるおそれがある。

重要な情報を一時ファイルに書き込む処理のあるプログラムが対象となる。

図26: テンポラリファイル

テンポラリファイル対策

テンポラリファイルとして格納したデータが漏えいしてしまう問題は、長期的に保管するデータでは無く、一時的に利用するだけという扱いにより、十分な注意が向けられないことから発生している。この対策としては、まず、テンポラリファイルに格納するデータに重要な情報(個人情報や暗号鍵、パスワード等)が含まれないようにすることであるが、重要な情報の格納が必要な場合には、次のような項目に注意する必要がある。

プログラム専用のテンポラリディレクトリを使う

サービスを提供するデーモンプログラム等は、/tmp 等の共通のディレクトリを使用せずに、次のようにプログラム専用のテンポラリディレクトリを作成し、そこにテンポラリファイルを作成するようにする。

このようにすると、他のユーザからの干渉が避けられ、情報は漏洩しにくくなる。

使用を避けた方がよい関数

以下の3つの関数は、現在でも使用できるが、脆弱性があるため使用を避ける。

その代わりに、以下に述べらている脆弱性が解消された mkstemp(3) 又は tmpfile(3) を使用するようにする。

予測困難なファイル名にする

mkstemp() 関数や tmpfile() 関数を使うことで,安全で適切なテンポラリファイルの作成が可能である。これらの関数は以下の3つの注意点をすべて網羅している。

1) int mkstemp(char *template);

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" のような文字列が返される。

2) FILE *tmpfile(void);

tmpfile()関数はmkstemp()関数を使いやすくした位置付けのものである。具体的には次のような動作をする。

厳重なアクセス権を選定する

テンポラリファイルのオープンは、本人のみが読み書きできるようにし、排他モードでオープンする。
テンポラリファイルを open() により作成するのであれば、次の例のようにパラメータを指定する。

fd = open(path,  S_IRUSR | S_IWUSR, O_CREAT | O_RDWR | O_EXCL);

・S_IRUSR|S_IWUSR (=0600)
   S_IRUSR (=0400)        ユーザーに読み込みを許可する
   S_IWUSR (=0200)        ユーザーに書き込みを許可する

・mode = O_CREAT|O_RDWR|O_EXCL
   O_CREAT                ファイルが無ければ作成する
   O_RDWR                 読み書き用にオープンする
   O_EXCL                 ファイルが既に存在したらエラーとする
                          (O_CREATと合わせて使用する)
   O_CREAT|O_RDWR|O_EXCL  ファイルを作成オープンし,
                          すでに存在したらエラーとする

シンボリックリンクをチェックする

シンボリックリンク攻撃は、攻撃者が /tmp 等に読み書きするファイルを予測し、そのファイルが別なファイルを指すようにシンボリックリンクを張り、別なファイルにアクセスするように仕向けるものである。

シンボリックリンク攻撃の対策については、本コンテンツの別記事「シンボリックリンク攻撃対策」を参照されたい。

ファイルを作成したら unlink する

テンポラリファイルを作成し、使用し終わったらクローズ 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のテンポラリファイル

Windowsの場合、mkstemp() のような関数は Win32 APIには存在しない。Win32 API の GetTempPath() 関数により、テンポラリファイルのディレクトリを取得できるが、ランダムなファイル名を作成する APIは用意されていない。このため信頼性のある乱数等を使用して、ファイル名を作成する必要がある。

※GetTempFileName() という関数があるが、これはファイル名の一意性を保障するのみで、推測困難なランダムなファイル名を作成するわけではない。