JPCERT コーディネーションセンター

FIO06-C. 適切なパーミッションを持つファイルを作成する

FIO06-C. 適切なパーミッションを持つファイルを作成する

パーミッションが十分に制限されていないファイルを作成すると、権限のないユーザがそのファイルにアクセスできてしまう。パーミッションの仕組みはファイルシステムに大きく依存するが、ファイル作成関数の多くは、パーミッションを設定する(または少なくともパーミッションに影響を及ぼす)仕組みを提供している。これらの関数を使用してファイルを作成する際は、意図しないアクセスを防ぐために、適切なパーミッションを指定する必要がある。

パーミッションを設定する際は、攻撃者が設定を変更できないようにすることが重要である(「FIO15-C. ファイル操作はセキュアなディレクトリで行われることを保証する」を参照)。

違反コード (fopen())

fopen() 関数を使うと、プログラマは明示的にパーミッションを指定できない。以下のコード例では、fopen() を呼び出して新規ファイルを作成した場合、パーミッションは処理系定義となる。

char *file_name;
FILE *fp;

/* file_name を初期化 */

fp = fopen(file_name, "w");
if (!fp){
  /* エラー処理 */
}
処理系固有の詳細

POSIX 適合システム上では、POSIX 関数 umask() の値によってファイルを新規に作成する際のパーミッションを制限できる [Open Group 04]。

POSIX は umask を反転させた値と、プロセスから要求された権限の論理積を計算することで、パーミッションを変更する [Viega 03]。たとえば、変数 requested_permissions の内容が、新しいファイルを作成するためにオペレーティングシステムに渡された権限だとすると、変数 actual_permissions の内容が、そのファイルを作成するためにオペレーティングシステムが実際に採用したパーミッションの値となる。

requested_permissions = 0666;
actual_permissions = requested_permissions & ~umask();

OpenBSD と Linux の場合、新規作成するファイルのパーミッションは、S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH(0666) をプロセスの umask 値で変更した値となる(OpenBSD マニュアルページの fopen(3) を参照 [OpenBSD])。

適合コード (fopen_s() ISO/IEC TR 24731-1)

ISO/IEC TR 24731-1 の関数 fopen_s() を使用して、パーミッションを制限したファイルを作成することができる[ISO/IEC TR 24731-1:2007]。

ファイル作成時のアクセスモードの 1 文字目が 'u' でなければ、そのファイルは、対象となるシステムの対応範囲内で、システムの他のユーザからのアクセスを防ぐ権限が設定される。ファイル作成時のアクセスモードの 1 文字目が 'u' ならば、そのファイルは、閉じるまでシステムのデフォルトのファイルアクセス権限が設定される。

文字 u は、"umask" を表すと考えることができる。つまり、1 文字目が u で始まるアクセスモードは、fopen() でファイルを作成した場合に設定されるパーミッションと同じパーミッションを意味する。以下の解決法では、モード文字 u が指定されていないため、ファイルは(umask に関係なく)制限されたパーミッションで作成される。

char *file_name;
FILE *fp;

/* file_name を初期化 */

errno_t res = fopen_s(&fp, file_name, "w");
if (res != 0) {
  /* エラー処理 */
}
違反コード (open()、POSIX)

POSIX の open() 関数を使用し、パーミッションを指定せずにファイルを作成した場合、そのファイルのパーミッションは過度に緩く設定される場合がある。このようにパーミッションを省略すると、たとえば CVE-2006-1174 のような脆弱性につながることがわかっている。

char *file_name;
int fd;

/* file_name を初期化 */

fd = open(file_name, O_CREAT | O_WRONLY);
/* パーミッションの指定がない */

if (fd == -1){
  /* エラー処理 */
}

このコード例は、「EXP37-C. API が意図した引数で関数を呼び出す」にも違反している。

適合コード (open()、POSIX)

新たに作成するファイルのパーミッションは、open() の第 3 引数で指定する必要がある。先の場合と同様に、パーミッションは umask() の値によって変更される。

char *file_name;
int file_access_permissions;

/* file_name と file_access_permissions を初期化 */

int fd = open(
  file_name,
  O_CREAT | O_WRONLY,
  file_access_permissions
);
if (fd == -1){
  /* エラー処理 */
}

John Viega と Matt Messier は次のような助言も行っている [Viega 03]。

プログラムの先頭で umask を「安全な」値に設定したとしても、非常に緩いパーミッションでファイルやディレクトリ作成関数を呼び出すのは避けること。ファイルのパーミッションは、作成時点で明示的に設定せよ。これには次の 2 つの理由がある。第 1 に、そのほうがコードがわかりやすく、パーミッションに関する意図が明確になるからである。第 2 に、umask の調整後、ファイル作成呼び出しまでの間に、攻撃者が何らかの方法で umask をリセットした場合、誰でもアクセスできるようなパーミッションで、機密ファイルを作成してしまう可能性があるからである。
リスク評価

制限の緩いパーミッションでファイルを作成すると、ファイルへの意図しないアクセスを許すことになる。

レコメンデーション 深刻度 可能性 修正コスト 優先度 レベル
FIO06-C P4 L3
参考情報
翻訳元

これは以下のページを翻訳したものです。

FIO06-C. Create files with appropriate access permissions

Top へ

Topへ
最新情報(RSSメーリングリストTwitter