PHPのクエリパラメーターの扱い方について
3年ぶりの更新というわけで、まさしく3年寝太郎状態なわけですが。
今日は今巷を賑わせているJSON SQL Injectionについてです。
徳丸さんの記事で紹介されていたように、僕が作ったSQL_Abstractでも同様の問題が発生するとのことです。
SQL::Makerのようにstrictモードを導入するかどうかも一応考えたのですが、PHP版SQL_Abstract自体PHP5でも動作はしますがPHP4時代のコードですし、そもそもそんなに使われてないだろう(泣)いうことで今回は見送ることにしました。(ちょっと今すぐ時間が取れないという状況もありまして・・・)
またstrictモードを導入したとしてもSQL_Abstractを配列で使いたいケースが結構多いと思うので結局strictモードを外して運用になるのではないかと思うので効果としては薄いのかなぁとも感じています。
でまぁSQL_Abstractではstirctモード導入しないよ!勝手に対策してよ!だとあまりに無責任な気がするので、この問題に対して僕が実際にやってる対策の一つをここで紹介しておきます。
PHPのクエリが配列で取れてしまう問題というのは、これはSQL_Abstractとの相性の問題というよりは、クエリが配列で来くることを想定していないのが問題であり、そこの部分を根本的に解決しない限り他のあらゆる箇所でバグが発生する原因になるとおもいます。
徳丸さんの記事では
strictモードが使えない場合は、条件設定に与える引数の型チェックを行う方法があります。
$user_name = $_GET['user_name']; if (! is_string($user_name)) { # エラー処理 exit; }
このようにis_string等を使ってチェックする必要があるとのことでしたが、僕は根っからの面倒臭がり屋なのでいちいち毎回チェックしてエラー処理したりするのが面倒なので面倒を避けるために以下のように処理しています。
<?php // そのまま返すやーつ function get_param($key) { if ( isset($_GET[$key]) ) { return $_GET[$key]; } return null; } // 常にひとつだけ返すやーつ function get_value($key) { return _get_scalar(get_param($key)); } function _get_scalar($param) { return is_array($param) ? _get_scalar(array_shift($param)) : $param; } // hoge.php?user_name[<>]=1とか渡されても大丈夫! $where = array( 'user_name'=> get_value('user_name') );
上記のようなラップ関数を用意し、get_value関数を使ってクエリパラメータがどういう状態で渡されても常にひとつの値だけを取る様にしてます。
以上、ありあしたッ!