« セッションのセキュリティ
Null バイト関連の問題 »

ファイルシステムのセキュリティ

目次

PHP には、多くのサーバーシステムに組み込まれている、 ファイル単位・ディレクトリ単位の権限によるセキュリティが適用されます。これにより、ファイ ルシステム内のファイルを読み込み可能に制御することが可能になります。 誰でも読み込めるファイルについては、 そのファイルシステムにアクセスできる全てのユーザーが読み込んでも安全であるよう、 注意する必要があります。

PHPは、ファイルシステムにユーザーレベルのアクセスを許可するように設 計されているため、PHPスクリプトから /etc/passwd のようなシステム ファイルを読み込み可能としたり、イーサネット接続を修正したり、巨大 なプリンタジョブを出力したりすることができます。これから明らかにわ かることですが、読み書きするファイルを適切に設定する必要があります。

各自のホームディレクトリにあるファイルを削除する次のスクリプトを見 てみましょう。これは、ファイル管理用にWebインターフェイスを使用す る場合に通常生じるような設定を仮定しています。この場合、Apacheユー ザはそのユーザーのホームディレクトリにあるファイルを削除可能です。

例1 甘い変数の確認から生じるリスク

<?php

// ユーザーのホームディレクトリからファイルを削除する
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir  = "/home/$username";

unlink("$homedir/$userfile");

echo "ファイルは削除されました!";

?>
username および filename はユーザーフォームから投稿可能であるため、他人の username および filename を投稿して、 本来は削除できないはずのファイルを削除できてしまいます。この場合、 他の何らかの形式の認証を使用するべきです。投稿された変数が、 "../etc/" と "passwd" であった場合について考えてみましょう。簡単 なコードを以下に示します。

例2 ... ファイルシステムへの攻撃

<?php

// 外部からPHPユーザーがアクセス可能なハードドライブを削除します。PHPが
// ルートのアクセス権限を有している場合、
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir  = "/home/$username"; // "/home/../etc"

unlink("$homedir/$userfile"); // "/home/../etc/passwd"

echo "ファイルは削除されました!";

?>
こうした問題を防止するために必要な重要なチェック手段として以下の2 種類のものがあります。
  • PHP Webユーザーバイナリに制限された権限のみを許可する。

  • 投稿された全ての変数を確認する。

以下に改良されたスクリプトを示します。

例3 より安全なファイル名の確認

<?php

// PHPユーザーがアクセス可能なハードドライブからファイルを削除する。
$username = $_SERVER['REMOTE_USER']; // 認証機構を使用する
$userfile = basename($_POST['user_submitted_filename']);
$homedir  = "/home/$username";

$filepath = "$homedir/$userfile";

if (file_exists($filepath) && unlink($filepath)) {
    $logstring = "$filepath を削除しました\n";
} else {
    $logstring = "$filepath の削除に失敗しました\n";
}

$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);

echo htmlentities($logstring, ENT_QUOTES);

?>
しかし、これでも、傷口を塞いだことにはなりません。 ユーザーが自分用のユーザーログインを作成することをあなたの認証システムが 許可しており、ユーザーが "../etc/" へのログインを選択した場合、システム はまたも公開されてしまいます。このため、よりカスタマイズされたチェッ クを行なう方がよいでしょう。

例4 より安全なファイル名の確認

<?php

$username     = $_SERVER['REMOTE_USER']; // 認証機構を使用する
$userfile     = $_POST['user_submitted_filename'];
$homedir      = "/home/$username";

$filepath     = "$homedir/$userfile";

if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
    die("Bad username/filename");
}

// etc.

?>

オペレーティングシステムによって、注意するべきファイルは大きく変化し ます。これらには、デバイスエントリ(/dev/ または COM1)、設定ファイル(/etc/ ファイルおよび .ini ファイル)、よく知られたファイル保存領 域 (/home/、My Documents)等が含まれます。このため、明示的に許可す るもの以外の全てを禁止する方針とする方が通常はより簡単です。

関連キーワード:
username   userfile   homedir   home   filename   ファイルシステム   セキュリティ   user   submitted   filepath   許可   passwd   確認   投稿   認証   logstring   問題   権限   安全   スクリプト   ホーム   変数   unlink   バイト   関連
関連する関数・ページ:
features.file-upload.multiple   security.filesystem.nullbytes   function.is-uploaded-file   security.variables   features.file-upload.post-method   wrappers.ssh2