安全を考えてPHPの実行時設定を調整する仕事で使える魔法のLAMP(37)

PHPを初期設定のまま使うと、いろいろ問題が起こる可能性があります。今回は、問題の発生を未然に防ぐ設定法をいくつか紹介します。(編集部)

» 2012年01月05日 00時00分 公開
[山口晴広株式会社イメージズ・アンド・ワーズ]

初期設定のままでは良くないところもある

 ここ数回はPHP実行時の設定について解説しています。実行時設定を変更する方法として、PHPの設定ファイル(以下php.iniファイル)に設定を記述する方法と、Apache HTTP Server(以下Apache)の設定ファイルにPHPの設定を記述する方法の2つがあり、前回はその使い分けについて解説しました。

 サーバ全体で標準の設定値としたいものはphp.iniファイルに、バーチャルホストやURLごとに変更したいものはApacheの設定ファイルに記述する、という使い分けの指針も示しました。

 今回は、php.iniで設定できる項目、つまりサーバ全体にかかわる設定項目の中でも、初期設定のままにしておくことがあまり適切でないものや、設定値を明示した方が、管理者にとって分かりやすくなる項目について説明します。まずは、安定性にかかわる部分について解説します。

使用できるメモリの量を制限

 前回前々回に紹介した設定項目「memory_limit」から説明しましょう。この設定項目はPHPのスクリプトが利用できるメモリ容量の最大値を決めるものです。初期設定では128Mbytesになっていますが、この設定の意味を考えると、小さくしておいた方がよいです。

 利用可能なメモリの量を制限するのは、スクリプトの作成ミスなどによって大量のメモリを消費してしまうことを防ぐためです。あるプロセスが大量にメモリを消費してしまうと、Apacheに接続しているほかのユーザーもメモリ不足の影響を受けてしまうことがあります。従って、標準の設定ではある程度小さくしておき、プログラムのミスなどの欠陥を検出しやすくしておくのがよいのです。

 あらかじめ大量にメモリを消費することが分かっている処理があるときは、Apacheの設定ファイルを利用したり、PHPの関数を利用することで、その部分だけ最大メモリ量を大きくすることもできます。もちろんこれは、部分的に設定を変更することの影響をしっかり把握してから慎重に設定しなければなりません。

 具体的に、どれくらいのメモリを利用可能と設定するか分かりにくいとおっしゃる方もいるでしょう。少なめにしたいときは16M〜32Mbytes、多めにするときは64M〜128Mbytesといったところが目安になると思います。もちろん、利用するフレームワークやアプリケーションによっては、最低値の指定がある場合も考えられます。

 なお、設定した値以上のメモリを使用するとFatal Error(致命的なエラー)となって、その時点でプログラムが停止します。これを嫌って、本番環境では「無制限」としてしまうこともあります。無制限と設定するには、設定値を「-1」とします。もちろん、無制限に設定するときは開発環境などで十分にテストをしておく必要があります

 設定した最大メモリ量を完全に消費すると、図1のような画面が現れます。

図1 設定した最大メモリ量を完全に消費したときに現れるエラーメッセージ。 図1 設定した最大メモリ量を完全に消費したときに現れるエラーメッセージ。クリックすると拡大

 図1のエラーは、次のような単純なPHPのスクリプトで再現できます。ループで配列に値を設定することを繰り返し、巨大な配列を作ってしまうのです。

<?php
for ($i=0; $i<10000000; $i++) {
    $a[$i] = $i;
}
?>

スクリプト実行時間を制限する

 設定項目「memory_limit」は、使用できるメモリ量を制限するものでした。これに対して、スクリプト実行時間を制限するのが、設定項目「max_execution_time」です。これは、memory_limitと同様、ミスなどによって処理が終了せずに延々と続いてしまうことを防ぐために使います。

 スクリプトの実行が続いていると、プロセッサ時間を消費し続けます。これが延々と続くと、Apacheに接続しているほかのユーザーのために使わなければならないプロセッサ時間もなくなってしまい、悪影響を与えることになります。

 memory_limitと同様に、あらかじめ処理に時間がかかることが分かっているスクリプトを実行するときは、設定値を大きくすることもできます。ただし、スクリプトを実行している間は、ユーザーのWebブラウザから見ると待ち状態が続いていることになるので、ユーザーが待ちきれずにWebブラウザの「中止」ボタンを押してしまうことも考えられます。さらに、Apacheの設定にはタイムアウトになるまでの時間を設定する項目があります。この設定値を超えてしまうと、PHPの設定に関係なくスクリプトの処理が終了となってしまいます。

 つまり、処理に時間がかかるからといって、単純にmax_execution_timeの設定値を大きくすることは得策ではありません。こういうときは、時間のかかる処理をバックグラウンドで実行するようにして、WebページをすぐにWebブラウザに返すようにするのが良いでしょう。その後、Webページ上のJavaScriptからサーバに対して処理が完了しているかどうかを問い合わせるようにします。

 max_execution_timeの設定にはもう1つ注意してほしい点があります。この設定で制限できる実行時間とは、PHPスクリプトの処理時間のみを指しています。例えば、データベースにアクセスしたときの応答が返ってくるまでの待ち時間などは含みません。あくまでPHPスクリプトの処理時間を限定するためのものです。データベースの反応が遅くなるときは、どの処理に時間がかかっているのかを検出する必要がありますが、これはMySQLの設定に進んだときに解説します。

 max_execution_timeの初期設定値は30秒です。特別な事情がない限り、この設定値が妥当だと筆者は考えます。そして、制限をなくすには「0」と設定します。

PHPを使っているという事実を隠す

 PHPは、初期設定のままではそのバージョン番号をHTTPのヘッダ情報に入れるようになっています。攻撃者から見ると、PHPのバージョンが攻撃の手掛かりになることもあります。従って、バージョン番号は公開しない方がよいでしょう。

 さらに、第34回でも触れたように、PHPを使っていること自体を隠したい場合もあります。これを隠すには設定項目「expose_php」の値を「Off」にします。

 また、第24回では、Apacheの設定ディレクティブ「ServerTokens」を使って、ApacheのバージョンをHTTPのヘッダ情報に入れないように設定しています。これも攻撃の手掛かりを与えないという同じ理由によるものでした。では、HTTPのヘッダ情報には、サーバの状態を示す情報がどれだけあるのかを見てみましょう。いったんServerTokensの設定を変更して、すべての情報をHTTPヘッダに表示するようにします。

 ヘッダ情報を見るにはいくつか方法がありますが、今回はcurlコマンドを使います。curlは引数で指定したURLにアクセスして、データをダウンロードするコマンドです。「-I」を引数に指定するとヘッダ情報だけを表示させることができます。では、前回まで使っていたphpinfo()の実行結果を表示するURLにアクセスしてみましょう。

$ curl -I http://www3026ub.sakura.ne.jp/phpinfo.php
HTTP/1.1 200 OK
Date: Thu, 05 Jan 2012 03:10:43 GMT
Server: Apache/2.2.21 (Unix) PHP/5.3.8
X-Powered-By: PHP/5.3.8
Content-Type: text/html

 ヘッダの中に「X-Powered-By: PHP/5.3.8」という部分があります。X-で始まるヘッダは独自ヘッダです。「Server」ヘッダを見ると、Apacheのバージョンに加えてPHPのバージョンも分かります。ServerTokensの設定を完全表示にすると、ApacheのバージョンやOSに加えて、一部のApacheモジュールの情報もHTTPヘッダに流れるのです。

 ではここで、PHPの設定ディレクティブであるexpose_phpをOffにして再度ヘッダを取得してみましょう。

$ curl -I http://www3026ub.sakura.ne.jp/phpinfo.php
HTTP/1.1 200 OK
Date: Thu, 05 Jan 2012 03:16:57 GMT
Server: Apache/2.2.21 (Unix)
Content-Type: text/html

 「X-Powered-By」ヘッダが消え、「Server」ヘッダからもPHPの情報がなくなりました。これでヘッダの情報からは、サーバでPHPを使っているということが分からなくなりました。さらにServerTokensを最小表示に戻すと、次のようになります。

$ curl -I http://www3026ub.sakura.ne.jp/phpinfo.php
HTTP/1.1 200 OK
Date: Thu, 05 Jan 2012 03:20:22 GMT
Server: Apache
Content-Type: text/html

 ApacheのバージョンやOSもHTTPヘッダからは読み取れなくなりました。攻撃者に与える情報を最小限にするという観点からすると、この状態が望ましいでしょう。

 expose_phpの設定値をOffにすると、もう1つ動作に変化があります。phpinfo()を実行したときの結果を表示する画面からPHPのロゴ画像が消えるのです。expose_phpがOn(初期設定)であるときは、phpinfo()の実行結果は図2のようになります。

図2 expose_phpの設定値がOnであるときに、phpinfo()を実行した結果。 図2 expose_phpの設定値がOnであるときに、phpinfo()を実行した結果。クリックすると拡大

 expose_phpの設定値をOffにして、phpinfo()を実行すると、結果を表示する画面からPHPのロゴが消えます(図3)。

図3 expose_phpの設定値をOffにして、phpinfo()を実行した結果。 図3 expose_phpの設定値をOffにして、phpinfo()を実行した結果。クリックすると拡大

 これは、設定によって画像へのリンクが消えるというだけの話ではありません。この画像はPHPの実行環境に埋め込んであるもので、どんなPHPスクリプトであっても、URLの末尾に「?=PHPE9568F34-D428-11d2-A769-00AA001ACF42」という文字列を追加すると、このロゴを表示させることができるのです。phpinfo()を実行しないスクリプトであってもです。例えば先に紹介した、メモリを使い切ってしまうスクリプトの末尾にこの文字列を追加してもPHPのロゴを表示させることができます(図4)。

図4 スクリプトのURLの末尾に特定の文字列を追加するとPHPのロゴをWebブラウザに表示させることができる。 図4 スクリプトのURLの末尾に特定の文字列を追加するとPHPのロゴをWebブラウザに表示させることができる。クリックすると拡大

 PHPの動作環境がこんな動きを見せることをご存じの方はどれだけいらっしゃるでしょうか? ロゴが表示できるだけで何か悪影響があるわけではないものの、こういった予期しない動作を止めるためにもexpose_phpはOffにしておきましょう。

 ここまで解説した内容をphp.iniにまとめると、設定項目は次の通りになります。memory_limitなどの値についてはアプリケーションに応じて変更してください。

memory_limit = 32M
max_execution_time = 30
expose_php = Off

 次回は、リクエストデータをどう取り扱うかを決める設定項目について解説します。

著者紹介

株式会社イメージズ・アンド・ワーズ
代表取締役
山口晴広(やまぐち はるひろ)



「仕事で使える魔法のLAMP」バックナンバー

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。