Web aym.pekori.to

第 29章グローバル変数の登録機能の使用法

PHPの変更点で最も議論の対象となったのは、おそらく、PHP 4.2.0において PHPのディレクティブ register_globalsが デフォルトでONからOFFに変更された時でしょう。 当時、このディレクティブに依存することが一般的であり、多くの人は、 このパラメータの存在すら知らず、PHPの動作そのものであるというよう に考えていました。このページは、このディレクティブにより安全でな いコードを書く可能性があるということをこのページで説明しますが、 このディレクティブそのものが安全でないわけではなく、これを誤って使 用することが安全でないということを念頭においていてください。

register_globalsをonとした場合、この機能により、HTMLフォームから投 稿される変数と同時に、あらゆる種類の変数がスクリプトに注入される ことになります。これは、PHPにおいては変数の初期化が不 要であるということにも関係し、安全でないコードを書くことが極めて容 易になるということを意味します。困難な変更でしたが、PHPコミュニティ は、このディレクティブをデフォルトで無効とすることを決定しました。 onとした場合、どこから来たのかが不明であり、出処を仮定するしかない 変数を使用することになります。スクリプト自体で定義される内部変数は、 ユーザにより送信されたリクエストデータと混ざってしまいますが、 register_globals を無効とすることでこれを回避することができます。 以下にregister_globalsの誤った使用例を示しましょう。

例 29-1. register_globals = on の誤った使用例

<?php
// ユーザが認証された場合のみ $authorized = true を定義する
if (authenticated_user()) {
    
$authorized = true;
}

// 最初に$authorizedをfalseとして初期化していないため、
// 以下のコードにより、GET auth.php?authorized=1 のように
// register_globals機能により定義される可能性があります。
// このため、誰でも認証されたようにみせることができます!
if ($authorized) {
    include
"/highly/sensitive/data.php";
}
?>

register_globals = onとした場合、上記のロジックは破綻する可能性が あります。offの場合、$authorizedはリクエストに より設定することはできず、正しく動作します。しかし、一般に良いプロ グラミング法は、変数を最初に初期化することです。例えば、上の例で $authorized = falseを先頭に置いておくことができ ます。これにより、ユーザはデフォルトで認証されない状態となるため、 register_globalsのon/offによらず上記のコードは動作します。

別の例は、 セッションに関するも のです。register_globals = onとした場合、以下の例で $usernameを使用することもできますが、 (URLにより)GETのような他の手段によっても $username を設定することができることに留意する 必要があります。

例 29-2. register_globals on またはoffの場合のセッションの使用例

<?php
// $usernameの出処は不明だが、$_SESSIONがセッションデータであることは
// 既知です。
if (isset($_SESSION['username'])) {

    echo
"Hello <b>{$_SESSION['username']}</b>";

} else {

    echo
"Hello <b>Guest</b><br />";
    echo
"Would you like to login?";

}
?>

偽造が試みられた時に警告するために予防的な計測を行うことも可能です。 ある変数の出処を前もって正確に知っている場合、 投稿されたデータが適切な投稿元からのものであるかを調べることができ ます。これは、データが偽造されたものでないことを保証するわけではあ りませんが、攻撃者による偽造の成立を限定的なものにすることができま す。リクエストデータの出処を気にかけない場合、 $_REQUEST を使用することができます。 この変数には、GET、POST、COOKIEが合わさって含まれています。 本マニュアルの PHPの外部変数の セクションを参照してください。

例 29-3. 簡単に変数汚染を検出する

<?php
if (isset($_COOKIE['MAGIC_COOKIE'])) {

    
// MAGIC_COOKIE comes from a cookie.
    // Be sure to validate the cookie data!

} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {

   
mail("admin@example.com", "Possible breakin attempt", $_SERVER['REMOTE_ADDR']);
   echo
"Security violation, admin has been alerted.";
   exit;

} else {

   
// MAGIC_COOKIE isn't set through this REQUEST

}
?>

もちろん、register_globalsをoffにするだけでは、使用するコードが安 全であることを意味しません。投稿された全てのデータ毎に 他の手段で検証することも必要です。ユーザデータを常に検証し、 使用する変数を初期化してください! 初期化されていない変数を調べるには、 error_reporting()E_NOTICEレベルのエラーを有効にするように してください。

register_globalsをOnまたはOffのエミュレートに関数情報に ついては、FAQを 参照してください。

スーパーグローバル: 使用可能なバージョンに関する注意: PHP 4.1.0 以降、 $_GET, $_POST, $_SERVER 等のスーパーグローバル配列が使用可能となっています。 詳細な情報については、マニュアルの superglobals のセクションを参照してください。