FIO01-C. ファイル名を使用してファイルを識別する関数の使用に注意する
ファイルに関するセキュリティ上の脆弱性の多くは、ファイル名が実際のファイルオブジェクトと強く紐付けられていないために、プログラムが意図しないファイルオブジェクトにアクセスすることによって発生する。ファイル名はファイルオブジェクトそのものの特性に関する情報を提供しない。さらに、ファイル名とファイルオブジェクトとの対応付けはファイル名を使った処理の度に確認される。ファイル記述子と FILE ポインタは、オペレーティングシステムによって対象となるファイルオブジェクトに紐付けられる(「FIO03-C. fopen() を使用したファイル作成時に何らかの仮定をしない」を参照)。
ファイル名ではなく、ファイル記述子や FILE ポインタを通じてファイルにアクセスすることで、実際の操作対象が意図するオブジェクトである確度が大幅に高まる。 できるだけ、ファイル記述子または FILE ポインタを通じてファイルにアクセスすることを推奨する。
以下の C99 関数は、ファイル名のみを使ってファイルを識別する。
- remove()
- rename()
- fopen()
- freopen()
これらの関数は注意して使用すること。「FIO10-C. rename() 関数の使用には注意する」、および「FIO08-C. オープンファイルに対する remove() の呼び出しには注意する」を参照。
違反コード
以下のコード例では、file_name で識別されるファイルをオープンして処理し、クローズし、削除している。しかし、remove() の呼び出しにおいて file_name で識別されるファイルオブジェクトが、fopen() の呼び出しにおいて file_name で識別されるファイルオブジェクトとは異なる可能性がある。
char *file_name; FILE *f_ptr; /* file_name を初期化 */ f_ptr = fopen(file_name, "w"); if (f_ptr == NULL) { /* エラー処理 */ } /*... ファイルの処理 ...*/ if (fclose(f_ptr) != 0) { /* エラー処理 */ } if (remove(file_name) != 0) { /* エラー処理 */ }
適合コード
信頼できないユーザによるファイル操作を防ぐように設定されたセキュアなディレクトリでファイルを開く以外に、削除するファイルと、その前にアクセスしていたファイルが同じであることを確実にする方法はない(「FIO15-C. ファイル操作はセキュアなディレクトリで行われることを保証する」を参照)。
違反コード (POSIX)
以下のコード例は、関数 chmod() を呼び出してファイルの権限を設定している。しかし、file_name が指すファイルオブジェクトが、fopen() や chmod() の呼び出しでアクセスするファイルオブジェクトと同じかどうかは不明である。
char *file_name; FILE *f_ptr; /* file_name を初期化 */ f_ptr = fopen(file_name, "w"); if (f_ptr == NULL) { /* エラー処理 */ } /* ... */ if (chmod(file_name, S_IRUSR) == -1) { /* エラー処理 */ }
適合コード (POSIX)
以下の解決法は、POSIX 関数の fchmod() と open() を使用している [Open Group 04]。こうすることで、オープンしたファイルと操作するファイルが同一であることが保証される。
char *file_name; int fd; /* file_name を初期化 */ fd = open( file_name, O_WRONLY | O_CREAT | O_EXCL, S_IRWXU ); if (fd == -1) { /* エラー処理 */ } /* ... */ if (fchmod(fd, S_IRUSR) == -1) { /* エラー処理 */ }
脅威の緩和策 (POSIX)
ファイル関連の競合状態の多くは、以下の関数を使用することで回避できる。
- fchown() を chown() の代わりに使用
- fstat() を stat() の代わりに使用
- fchmod() を chmod() の代わりに使用
または、「FIO15-C. ファイル操作はセキュアなディレクトリで行われることを保証する」に従って、作業ディレクトリのセキュリティを確保する。
ファイル記述子を使う同等な関数がない以下の POSIX 関数は注意して使用すること。
- link() および unlink()
- mkdir() および rmdir()
- mount() および unmount()
- lstat()
- mknod()
- symlink()
- utime()
リスク評価
TOCTOU(time of check、time of use) 競合状態などのファイル関連の脆弱性の多くを悪用すると、プログラムに、意図しないファイルへのアクセスを行わせることができる。ファイル名の代わりに FILE ポインタやファイル記述子を使用してファイルを識別することで、意図しないファイルへアクセスする可能性は低くなる。セキュリティの低い関数は簡単に識別できるが、簡単な置き換えができないこともあるため、修正コストは中になっている。
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO01-C | 中 | 高 | 中 | P12 | L1 |
自動検出
LDRA tool suite Version 7.6.0 はこのレコメンデーションの違反を検出できる。
Compass/ROSE はこのレコメンデーションの違反のいくつかを検出できる。特に、オープンしているファイルに対して chown()、stat()、または chmod() を呼び出している場合を検出できる。
Klocwork Version 8.0.4.16 では、SV.TOCTOU.FILE_ACCESS チェッカーを使ってこのレコメンデーションの違反を検出できる。
参考情報
- [Apple Secure Coding Guide] "Avoiding Race Conditions and Insecure File Operations"
- [Drepper 06] Section 2.2.1 "Identification When Opening"
- [ISO/IEC 9899:1999] Section 7.19.3, "Files," and Section 7.19.4, "Operations on Files"
- [MITRE 07] CWE ID 73 "External Control of File Name or Path," CWE ID 367, "Time-of-check Time-of-use Race Condition," and CWE ID 676, "Use of Potentially Dangerous Function"
- [Open Group 04] "The open function"
- [Seacord 05a] Chapter 7, "File I/O"
翻訳元
これは以下のページを翻訳したものです。
FIO01-C. Be careful using functions that use file names for identification