変数汚染のリスク
変数汚染はグローバル変数やスーパーグローバル変数の値が改ざんされることを指します。外部からの受け取ったリクエスト値をそのまま変数展開させてしまう場合に発生します。セッション変数を改ざんされてしまった場合、コマンドを実行されたり、権限を与えてしまうといったリスクが高まります。
変数汚染の原因
古いバージョンのPHPで「register_globals = On」となっている場合。PHP4.2.0以降ではデフォルトでOffになっています。また、PHP5.3.0で非推奨となり、PHP5.4.0で削除されました。しかし、foreachやextractの配列処理機能でスーパーグローバル変数の自動展開をしている場合は、変数汚染によるリスクが高まります。また、import_request_variables()関数でのGETやPOSTなどによる変数展開、parse_str()関数を使ったリクエスト文字列の変数展開をしている場合も該当します。
以下のコードにおいて「?_SERVER[HTTP_HOST]=aabbcc」といった感じで「=」以降に適当な文字列を入れてアドレスバーからGET送信すると、スパーグローバル変数である$_SERVER['HTTP_HOST']にその適当な文字列が代入されて表示されてしまいます。
foreach($_GET as $key => $val){
$$key = $val;
}
echo 'スパーグローバル変数HTTP_HOST:'.$_SERVER['HTTP_HOST'];
$$key = $val;
}
echo 'スパーグローバル変数HTTP_HOST:'.$_SERVER['HTTP_HOST'];
対処法
「register_globals」を無効にしてforeachやextractなどで変数展開せず、$_GET[変数名]といったように記述することでほとんど防御できます。。
変数汚染を防ぐ変数をブラックリスト化
汚染を防御する変数をブラックリストに登録します。
$black=[GLOBALS, _SERVER, _ENV, _GET, _POST, _REQUEST, _COOKIE, _SESSION, _FILES];
foreach([$_GET, $_POST, $_COOKIE] as $val){
foreach($black as $global){
if(isset($val[$global]) === true){exit;}
}}
foreach([$_GET, $_POST, $_COOKIE] as $val){
foreach($black as $global){
if(isset($val[$global]) === true){exit;}
}}
処理する変数のみ展開
処理対象の変数をホワイトリストに登録します。
foreach($_GET as $key => $val){
if(in_array($key, [white_name1,white_name2]) === false){exit;}
$$key = $val;
}
echo 'スパーグローバル変数:'.$_SERVER['HTTP_HOST'];
if(in_array($key, [white_name1,white_name2]) === false){exit;}
$$key = $val;
}
echo 'スパーグローバル変数:'.$_SERVER['HTTP_HOST'];