Register globals
提供: GeeklogJpWiki
register_globalsの問題
バージョン1.4.0以降,GeeklogではもはやPHPのregister_globalsをオンにする必要はなくなりました。
register_globalsをオンにするのは"悪"であるという通念はありますが,以下の議論で示すいくつかの単純なルールに従いさえすれば,register_globalsそれ自体はセキュリティ上の問題にはなりません。Geelogでregister_globalsをオンにすることが要求されていた時代に,この設定が元で生じたセキュリティ問題はわずかに1つだけでした。
余談ですが,register_globalsの設定はPHP6では廃止されます。つまり,常にオフになり,オンにする方法はなくなるのです。だから,register_globalsの設定に依存するコードを見直すのに今はよいときでしょう。
目次 |
変数を初期化する
register_globalsの設定にまつわる問題を避ける主要なルールは極めて単純です。
変数を初期化せよ!
PHP 4.1.0の注には,"register_globals = on"の問題点を説明するのに次のような例が載っています。
<?php
if (authenticate_user()) {
$authenticated = true;
}
...
?>
"register_globals = on"の状態では,このスクリプトのURLに"authenticated=true"を追加するだけでこの認証チェックをくぐり抜けることができます。たとえば,
http://www.example.com/authenticate.php?authenticated=true
しかし,この問題に対処するのは簡単です。
<?php
$authenticated = false;
if (authenticate_user()) {
$authenticated = true;
}
...
?>
URLにどんなものを放り込んでも,$authenticated変数を初期化することでこの問題に対処できます。
いずれにせよ,セキュリティという観点にとどまらず,変数の初期化はよいプログラミング・スタイルです。自分のためになることなので,変数の初期化を行いましょう。
エラー表示をオンにする
開発に使っているシステムでは(実際に使用するサイトでは決して行ってはいけません),エラー表示をオンにして,初期化されていない変数が引き起こす問題を意識しましょう。
php.ini ファイルの中で,
error_reporting = E_ALL display_errors = On display_startup_errors = On
を指定します。変更したら,忘れずにWebサーバーを再起動してください。
次に,Geeklogのlib-common.phpで次の行を探します。
error_reporting( E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR );
そしてこの行をコメントアウトするか削除します。
注:lib-common.phpから上記のエラー表示を制御する行を削除すると,言語ファイル中の初期化されていない変数に関する警告メッセージが山のように表示されるでしょう。これらは簡単には修正できない歴史的な問題ですが,セキュリティの問題にはなりません。自分のコードでこのような設計上の問題を繰り返さないようにすればよいだけです。
言語ファイルが引き起こす警告メッセージのせいでサイトにログインできなくなる可能性があるので,開発サイクル中のデバッグ期間に限って上述の行をコメントアウトした方がよいかもしれません。
型を考慮した比較を行う
register_globals = onで作成される変数と同様,スーパーグローバル変数($_GET, $_POST, $_REQUESTなど)の内容も全て文字列です。したがって,型を考慮した比較を行うことにより,コードの安全性を高めることができます。
if ($authorized === TRUE)
{
// $authorized に論理型のtrueの値が入っているときしかマッチしない
}
register_globalsの隠れた問題点
"register_globals = on"を利用すると,検出できない形で配列に値を紛れ込ませることが可能になります。
$sids[] = "123";
foreach ($sids as $sid)
{
// sidを参照して記事を削除するコード
}
このコードでは,
somepage.php?sids[]=1&sids[]=2
のようなURLを使うことで,配列の中に値が紛れ込んでしまいます。
$_GET, $_POST, $_REQUESTを使う
上記では,register_globals = onのときに起こるセキュリティ上の問題を避ける方法を説明しましたが,もちろん,変数の初期化だけでは,register_globals = offとしてもコードが正常に動作するわけではありません。
ユーザとのやりとり,つまり,ユーザがURLをクリックしたり,フォームを送信したときに渡される変数は常にスーパーグローバル配列 $_GET と $_POST に渡されます。お探しの変数は,変数名をキーとしてこの2つの配列の中に存在しています。たとえば,
/index.php?page=2というURLからは,$_GET['page'] "title"というフィールドを持つコメントフォームからは,$_POST['title']
という具合です。 普通,フォームにはmethod="POST"という属性があるので,HTTP POSTリクエストとして送信されます。その結果,この場合は$_GET変数は空になり,フォームの変数はすべて$_PST配列の中にしかないことになります。
$_REQUEST配列は$_GET配列と$_POST配列の両方を含みます。これが便利なのは,GETリクエストでもPOSTリクエストでも変数が渡される可能性がある場合です。
しかしながら,クラッカーが不正なリクエストを送りやすくなるので,$_REQUEST配列は注意深く控え目に使うべきです。たとえば,フォームを処理するコードが$REQUEST配列しか調べていない場合,フォームの全ての変数を1回のGETリクエストで送る込むことが可能になるため,状況によっては,POSTリクエストを送るよりも簡単になってしまいます。
とはいえ,$_REQUESTを使うことによりセキュリティ上の影響は限られたものです。でも,コードをより明確にするために,入力データが$_GETに入るのか$_POSTに入るのかはっきりわかるコードを書くことをお勧めします。
register_globalsをオフにする
開発に使用するシステムでは,php.iniの中でregister_globalsをオフにした方がよいでしょう。
register_globals = Off
register_long_arrays
register_globalsといくぶん関係ある設定がPHP5で導入されました。register_long_arraysをオンにすると,$_GET配列と$_POST配列が長い名前,すなわち,$HTTP_GET_VARSと$HTTP_POST_VARSが参照できようになります。これらの長い名前の配列はPHP5ではデフォルトで無効にされており,依存するコードはうまく動作しないことになります。
長い配列の代わりとなるものが上述の$_GETと$_POSTであり,この2つだけを使うべきです。この2つはPHP 4.1.0で導入されましたが,これはGeeklogが動作する一番古いバージョンでもあります。