PHP は強力な言語そしてインタプリタであり、 モジュールとして Web サーバーに組み込んだ場合でも、 独立した CGI バイナリとして実行される場合でも、 ファイルをアクセスしたり、コマンドを実行したり、サーバーへの ネットワーク接続を開くことができます。 デフォルトでは、これらの機能を実行した場合、Webサーバー上で セキュリティ上の問題を生じる可能性があります。 PHP は、特に CGI プログラムを書く場合、Perl や C より安全な言語と なるように設計されています。 コンパイル時または実行時の設定オプションを正しく選ぶことにより、 必要な自由度とセキュリティの組み合わせを確実に提供することができます。
PHP の使用法に多くの異なった手段があるように、 PHP の動作を制御する多くの設定オプションがあります。 オプションの選択肢が広いため、PHP を様々な用途に使用することが できます。 しかし、このことは、これらのオプションとサーバー設定の組み合わせに よっては、安全でない設定となることを意味します。 本章は、異なった設定オプションの組み合わせと安全に使用可能な 状況について説明します。
PHP を CGI バイナリとして使用する のは、 PHP をモジュールとして(Apache のような)サーバーソフトウエアに 組み込みたくない何らかの理由がある場合や 安全な chroot と setuid 環境をスクリプトに提供する 他の CGI ラッパーと組み合わせて PHP を使用する場合の 設定オプションです。 セットアップ時には、通常、PHP 実行バイナリを Web サーバーの cgi-bin ディレクトリにインストールします。 CERT 勧告 CA-96.11 は、いかなるインタプリタを cgi-bin に置くことにも反対しています。 PHP バイナリをスタンドアロンのインタプリタとして使用することが できる場合でも、PHP は、セットアップにより生じる可能性がある 次のような攻撃を防ぐように設計されています。
システムファイルへのアクセス: http://my.host/cgi-bin/php?/etc/passwd
URL において疑問符 (?) の後のクエリー情報は、CGI インターフェースに より、インタプリタにコマンドライン引数として渡されます。 通常、インタプリタは、コマンドライン上の最初の引数に 指定されたファイルを開き、実行します。
CGI バイナリとして実行された場合、PHP は、コマンドライン引数の 解釈を拒否します。
サーバー上の Web ドキュメントへのアクセス: http://my.host/cgi-bin/php/secret/doc.html
URL の PHP バイナリ名の後のパス情報の部分、つまり /secret/doc.html は、 CGI プログラムにより オープンされて実行されるファイルの名前を指定するために従来より 使用されています。 http://my.host/secret/script.php3 のようなドキュメントへの要求を PHP インタプリタにリダイレクト するために、通常、何らかの Web サーバー設定用命令(Apache では Action) が使用されます。 この設定により、Web サーバーは、まずディレクトリ /secret へのアクセス権をチェックし、 リダイレクト要求 http://my.host/cgi-bin/php/secret/script.php3 を生成します。 残念なことに、リクエストが最初からこの形式で与えられた場合、 Web サーバーによるアクセスチェックは、 /secret/script.php3 ファイル ではなく、/cgi-bin/php ファイル に対して行われます。 この手法により、/cgi-bin/php に アクセス可能なユーザーは、Web サーバー上の全ての保護された ドキュメントにアクセスできてしまいます。
PHP では、 サーバードキュメントツリーにアクセス制限付きのディレクトリが ある場合、 コンパイル時の設定オプション --enable-force-cgi-redirect および実行時の設定命令 doc_root とuser_dir を この攻撃を防止するために使用することができます。 これらを組み合わせたいくつかの手法について 以下に詳細な説明を示します。
サーバー上にパスワードまたは IP アドレスを元にしたアクセス制限 による制約を受けるコンテンツがない場合、 この設定オプションを使用する必要はありません。 使用する Web サーバーがリダイレクトを許可しない場合や サーバーがリダイレクト要求を安全に処理しつつ PHP バイナリと通信できる手段を有していない場合、 オプション --disable-force-cgi-redirect を configure スクリプトに指定することができます。 この場合でも、直接的な方法 http://my.host/cgi-bin/php/dir/script.php3 でもなくリダイレクション http://my.host/dir/script.php3 でもない他のやり方で PHP スクリプトを呼び出せるようになっていないか どうか確認する必要があります。
リダイレクションは、例えば Apache では命令 AddHandler および Action で設定することができます。(以下を参照してください。)
このコンパイル時のオプションは、 http://my.host/cgi-bin/php/secretdir/script.php3 のように URL から直接 PHP を呼び出すことを禁止します。 代わりに、 Web サーバーのリダイレクションにより処理された場合は、 PHP はこのモードでのみ処理を行います。
通常、Apache 用設定でのリダイレクションは、 次の命令を使用して行います。
Action php3-script /cgi-bin/php AddHandler php3-script .php3
このオプションは、Apache Web サーバーでのみテストされており、 リクエストのリダイレクト時に Apache が 非標準の CGI 環境変数 REDIRECT_STATUS をセットすることを 前提にしています。 リクエストが直接のものであるか間接のものであるかを示す手段をWeb サーバーが 全くサポートしていない場合は、このオプションを使用することはできません。 この場合、ここで記した CGI 版を実行する他の方法の内の一つを使用する必要があります。
Web サーバー上のドキュメントディレクトリに スクリプトや実行ファイルのようなアクティブな内容を読み込むのは、 往々にして危険な行為であるとみなされることがあります。 何らかの設定ミスによりスクリプトが実行されず、通常の HTML ドキュメント として表示されてしまう場合には、知的著作物またはパスワードのような セキュリティ情報が漏洩する可能性があります。 このため、多くのシステム管理者は、スクリプトを PHP CGI を通じてのみ アクセス可能な他のディレクトリ構造にセットアップしたいと思うこと でしょう。 この場合、常にインタープリタに処理されるため、上記のように表示されること はありません。
前節で記したようなリクエストがリダイレクトされたものでないことを 確かめる方法が利用可能でない場合、 スクリプト用の doc_root を Web ドキュメント用ルートとは別に セットアップする必要があります。
設定用命令 doc_root により 設定ファイル ファイル中で PHP スクリプト用ドキュメントルートを設定することができます。 または、環境変数 PHP_DOCUMENT_ROOT でも設定する ことができます。 これを設定した場合、CGI 版の PHP は、 常に開くファイルの名前をこの doc_root リクエストのパス情報を用いて作成し、 (以下の user_dir を除き、)確実に このディレクトリの外側でスクリプトが実行されないようにします。
ここで利用可能な別のオプションは、 user_dir です。user_dir が設定されていない場合、 開かれるファイル名を制御するのは、doc_root のみです。 http://my.host/~user/doc.php3 のような URL は、ユーザーホームディレクトリ以下のファイルを開かず、 doc_root 以下の ~user/doc.php3 というファイルを開くことになります。 (ディレクトリ名がチルダ [~] で始まっている ということになります)
user_dir が例えば、public_phpに 設定されていた場合、http://my.host/~user/doc.php3 のようなリクエストは、 そのユーザー user のホームディレクトリにある public_php 以下の doc.php3 という名前のファイルを オープンします。 ユーザーのホームディレクトリが、 /home/user である場合、 実行されるファイルは、 /home/user/public_php/doc.php3 となります。
user_dir の展開は、 doc_root の設定によらず行われます。 このため、ドキュメントルートおよびユーザーディレクトリへの アクセスを別々に制御することができます。
非常に安全性の高いオプションとして PHP パーサのバイナリをファイル用 Web ツリーの外側、 例えば /usr/local/binに 置くことが考えられます。 このオプションの唯一の欠点は、 PHP タグを有する全てのファイルの先頭行に次のような一行を 加える必要があることです。
#!/usr/local/bin/php
この設定で PATH_INFO および PATH_TRANSLATED 情報を正しく処理するためには、 PHP パーサを設定オプション --enable-discard-path を付けてコンパイルする必要があります。