TOP書籍連動> エスケープの落とし穴
SQLインジェクション
SQLインジェクション

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

著者:Ilia Alshanetsky   2006/1/25
1   2  3  次のページ
エスケープの落とし穴

   しかし、エスケープ関数を使えばいつでもデータの安全性が保障されるわけではありません。あるクエリに対しては、エスケープを適用した後でもSQLインジェクションを許してしまいます。Int型の値をとることを想定した次の場合について考えてみましょう。
$id = "0; DELETE FROM users";
$id = mysql_real_escape_string($id); // 0;
DELETE FROM users
mysql_query("SELECT * FROM users WHERE
id={$id}");

   Int型の時は、値をシングルクォートで囲う必要がありません。そのため、セミコロンでクエリが分割され、SQL文を不正に入れることができます。セミコロンには'特別'な意味はないため、データベースのエスケープ関数にもaddslashes()にもスルーされてしまいます。

   この問題には2つの解決策が考えられます。1つはユーザの値をすべてシングルクォートで囲うことです。シングルクォートはいつでもエスケープされるので、このテクニックを使えばSQLインジェクションを防げます。しかし、クォートを使うとユーザ入力をデータベースに送ることはできても、クエリの実行が拒絶される場合があります。このような例を見てみましょう。

$id = "0; DELETE FROM users";
$id = pg_escape_string($id);
// 0; DELETE FROM users
pg_query($conn, "SELECT * FROM users WHERE id='{$id}'")
or die(pg_last_error($conn));
// Int型として無効な構文を出力する:
// "0; DELETE FROM users"

   このようなクエリ実行の失敗は簡単に防ぐことができます。特に、クエリの検証が単純な時は簡単です。データベースにただ単に値を送るのではなく、PHPのキャストを使うことでそれぞれのデータの型を保証するのです。例として整数が必要な場合、入っているデータをint 型にキャストします。小数が必要なら、.oat型にキャストします。

$id = "123; DELETE FROM users";
$id = (int) $id; // 123
pg_query($conn, "SELECT * FROM users WHERE id={$id}");
// safe

   キャストすることでPHPが型変換を行います。入力が数値だけでなければ、最初の数値部分だけが使われます。入力が数値で始まっていなかったり、アルファベットや句読点だけの場合は、キャスト後の値は0になります。一方、キャストに成功すれば入力は適正な数値になるので他のエスケープは不要になります。

   数字のキャストは効果的な上にとても効率的です。というのもキャストはエスケープ処理を実行する関数を使わない、大変高速な処理だからです。

1   2  3  次のページ

PHPプログラマーズマガジン 書籍紹介
PHPプログラマーズマガジン

PHPプログラマーズマガジンは、PDF形式で読者の方にお届けするPHP言語(PHP: Hypertext Processor)専門誌です。 カナダMTA出版のphp|architect誌を日本語に翻訳し、独自の記事を加えて月刊でお届けしています。

発行:アシアル株式会社 価格:1,029円

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


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