TOP書籍連動> LIKEを使ったクエリ
SQLインジェクション
SQLインジェクション

第2回:クエリを使用したSQLインジェクション

著者:Ilia Alshanetsky   2006/1/25
前のページ  1  2   3  次のページ
LIKEを使ったクエリ

   LIKEを使った文は非常に便利です。%や_(アンダースコア)といった記号は0文字以上の文字列、どんな1文字にもマッチし、部分一致に幅広く使えるからです。しかし、LIKで使える%や_などはデータベースのエスケープ関数やPHPのマジッククォートには無視されます。

   結果、LIKEクエリに組み込まれたユーザ入力でクエリが変わってしまいLIKEのマッチングがおかしくなって多くの場合インデックスが使えなくなって実行速度が大幅に低下します。

   2、3回繰り返すだけでも、怪しげなLIKEクエリはデータベースに多大な負荷をかけるDOS(Denial of Service)アタックのようなものになりうるのです。ここで簡単に、その効果的な攻撃を見てみましょう。

$sub = mysql_real_escape_string("%something");
// still %something
mysql_query("SELECT * FROM messages "
. "WHERE subject LIKE '{$sub}%'");

   例で示したSELECT文は、subjectがユーザの指定した$subという文字列で始まるデータを、messagesテーブルから見つけるというものです。ぱっと見たところ、このSELECT文は検索にsubjectのインデックスを使用していれば非常に早く処理されるはずです。

   しかし、もし$subに%が含まれていたら、インデックスを使うことができないので処理するのに遥かに長い時間がかかってしまいます。実際、テーブルに入っているデータ量が増えると飛躍的に処理が遅くなります。

   アンダースコアも似ていますがまた別の問題を引き起こします。_ishのように、検索パターンの最初にアンダースコアがあると、インデックスを使用しても処理が早くならず、むしろ処理が遅くなります。そして連続したアンダースコアは大幅にクエリ実行結果を変えることがあります。

   さらに厄介なことに、アンダースコアは非常によく使われる文字なので、完全に適正な入力の中で使われていることもあります。LIKEクエリを指定するために、カスタマイズしたエスケープ機能ではユーザが入力した%や_を普通の文字に置き換えなければなりません。そこで、addcslashes()という関数を使って指定した文字列の範囲をエスケープします。

$sub = addcslashes(mysql_real_escape_string("%something_"),"%_");
// $sub == %something_
mysql_query("SELECT * FROM messages"."WHERE subject LIKE '{$sub}%'");

   ここでは、入力はまずデータベースのエスケープ関数で処理され、それから%や_をすべてエスケープするためにaddcslashes()関数に渡されます。addcslashes()関数はカスタマイズしたaddslashes()関数のようなもので、非常に効率的で、str_replace()関数や、それと同じ動作をする正規表現よりもずっと高速に処理することができます。

   バックスラッシュのエスケープを避けるためにSQLのフィルタを通した後で必ず手製のフィルタを適用するようにしてください。そうしないと、つけ加えられたバックスラッシュがエスケープされてしまい普通の文字になってしまうので、もともとエスケープしたかった特殊文字に再び特別な意味を持たせてしまうことになります。

前のページ  1  2   3  次のページ


Ilia Alshanetsky
著者プロフィール
Ilia Alshanetsky
PHP開発チームの活動メンバーの1人であり、現在のPHP 4.3.X.のリリースマネージャー。また、オープンソース掲示板FUDフォーラム(http://fud.prohost.org/forum/)をはじめとする数多くのプロジェクトにも貢献している。


INDEX
第2回:クエリを使用したSQLインジェクション
  エスケープの落とし穴
  LIKEを使ったクエリ
  SQLエラーハンドリング