PR

(注:記事は執筆時の情報に基づいており,現在では異なる場合があります)

 PHPはオープンソース・ソフトウエアという性格上,頻繁にバージョンアップしています。バグ修正なら早いに越したことはないのですが,ちょっと目を離したすきに仕様が変わってしまうこともあります。ステップ4では,PHPプログラマを慌てさせたregister_globalsの設定について説明します。

図1●リスト1を実行した画面
図2●正しいパスワード(php)が入力された場合の画面
表1●ユーザーの入力値を格納した配列変数
リスト1●管理者用パスワードを入力するHTMLフォーム(ontest.php)
リスト2●リスト1が呼び出すサーバーのPHPスクリプト(ontest-sub.php)
リスト3●register-globalsをOffにしても正しく動作するようリスト2を書き換えた
 C:\WINNTに作成したphp.iniをテキスト・エディタで開き,register_globalsという項目を探してみましょう。値がOffになっていますね。実は,古いバージョンのPHPではこの設定がOnでした。それがPHP 4.1.0で「セキュリティの改善のための新しい入力インタフェース」という改善が行われ,register_globalsをOffにして使用することが推奨されるようになり,PHP 4.2以降はデフォルトでOffになったのです。

register_globalsがOnによるメリット

 では,どうしてregister_globalsをOnにすると問題なのでしょう? そこで,いったんphp.iniの設定を

register_globals = On

としてApacheのサービスを停止し,再起動してみましょう。PHPのスクリプトを実際に動かして挙動を確かめたいと思います。

 リスト1(ontest.php)は,入力したパスワードが合致すれば,管理者用のプログラムを起動するHTMLフォームです(図1[拡大表示])。パスワードを入力して送信ボタンをクリックすると,postメソッドによってサーバーのontestsub.php(リスト2[拡大表示])にパスワードが送信され,パスワードが正しい場合に処理が行われるというわけです(図2[拡大表示])。パスワードが「php」であることはリスト2[拡大表示]を見ればわかりますね。

 実はこのプログラム,register_globalsがOnになっていないと正しく動作しません。Onになっていると,HTMLフォームにある<input>タグのname属性に設定した名前を,そのままグローバル変数として扱えるからです。リスト1[拡大表示]の(1)でname属性がpassnoとなっていますね。これが,リスト2[拡大表示]の(1)のように$passno変数の値として呼び出せるわけです。

 「便利じゃないか」――その通り。では,どうして4.2以降のバージョンではregister_globalsをデフォルトでOffにしたのでしょう。

素性がはっきりしない変数に要注意

 食品に対する信頼が揺らいだことで,牛肉を買うときにはラベルを注意深く見ることが多くなりました。和牛,国産,オーストラリア産…。今日はしゃぶしゃぶだから和牛にしようとか,安全そうだからオーストラリア産にしようとか考える人もいるでしょう。でも,ラベルに産地が書いてなかったり,書いてあっても嘘だったりすると困りますよね。

 実はregister_globalsがOnだと,どこから来た値(牛肉)なのかがわからないのです。ためしに,ブラウザのアドレス欄に「http://127.0.0.1/sample/ontestsub.php?passno=php」と入力して実行してみてください。なんと,図2[拡大表示]の画面が開いてしまったはずです。つまり,HTMLフォームからパスワードを入力しなくても,URLパラメータとしてパスワードを渡してしまうことで“管理者用の”プログラムを実行できてしまったわけです。HTMLフォームを経由せずに管理者用プログラムを実行できるのですから(もちろん,パスワードを事前に知っている必要がありますが),セキュリティ上問題があるのは当然ですね。そこでラベルのない(素性のはっきりしない)変数を使えなくするためにregister_globalsをOffにするようになったのです。

 では,register_globalsがOffの場合には,どうやってサーバー側で入力値を受け取ればいいのでしょう。結論から言うと表1[拡大表示]の連想配列を使って,経路別に入力値を扱うことになります。先ほどの例で言うなら,リスト2[拡大表示]の(1)の部分を,

if ($_POST['passno'] == "php"){

と書き換えてください(リスト3[拡大表示])。$_POST['passno']は,$_POSTに格納された値を,キーpassnoを使って取り出すという意味です。ラベル(postメソッドで送信された値であるという素性)がはっきりしていますね。

 register_globalsの設定を再びOffにしてApacheを再起動し,リスト1を実行してみましょう。前述のようなURLを入力されても大丈夫なことが確認できると思います。

グローバル変数は破棄しよう

 本セミナーで取り上げているPHPはバージョンが4.2.3であるため,皆さんが自分の環境でPHPアプリケーションを開発するなら,最初からregister_globalsがOffに対応したスクリプトを書けばいいでしょう。

 しかし,残念ながらPHPの世界は混沌としています。レンタル・サーバーやすでにPHPを運用しているサーバー・マシンでは,まだregister_globalsがOnのままになっているケースが少なくないのです。そんなサーバーで皆さんが作った新しいプログラムを動かすとなった場合,注意してほしいことがあります。

 それは,register_globalsがOnである限り,ブラウザから送信されたグローバル変数は“生きている”という点です。リスト2[拡大表示]をリスト3[拡大表示]のように書き換えたとしても,$passnoというグローバル変数が使えなくなるわけではありません。もし,うっかりスクリプトの中で,$passnoという変数名を使ってしまうと,そこには自動的にユーザーが入力したパスワードの値が入ってしまうことになります。これは思わぬバグの原因となるでしょう。

 そこで,register_globalsがOnの設定になっているサーバー用にプログラムを書く場合は,

unset($passno);

などとunsetコマンドを使って,あらかじめグローバル変数の値を破棄しておくことを覚えておくといいでしょう。

金宏和實(Kanehiro Kazumi)

■著者紹介 金宏和實(かねひろ・かずみ)氏

株式会社イーザー代表取締役副社長。富山県高岡市在住。