SQLインジェクションについて

ネタ元:$_GETを安易に受け入れちゃダメ!

前に書いたエントリー(re:キケンなSQLインジェクション)が誤解を与えてしまったようですので、もう少し補足しておきます。

まず、結論から書くと、

mysql_queryの場合はチェックが要らないって言ってるわけではないです。

そして、

mysql_real_escape_stringを過信してはいけません

様々なSQLインジェクション

複合クエリ

$sql="select * from geekDB where id = " . $_GET['id'];
$result = pg_query($sql); 

これは$_GET['id']の値が以下のような場合問題が発生します。

'';DELETE FROM geekDB;

テーブルを丸ごと消すことが可能です。

前回のエントリー(re:キケンなSQLインジェクション)でmysql_queryは複合クエリに対応していないので消すことができないと書いていますが、基本的にDBを考慮せずにこの対策は行ったほうがよいです。

脆弱性の多くが知らなくて発生しているのではなく、知っていて対処忘れが原因で発生するからです。対応する・しないを毎回考慮するのではなく、常に対応するの姿勢だと間違いが少なくなる為です。

WHERE句

$_GET['id']の値が以下のような場合にもSQLインジェクションが発生します。

'' OR effective=0

これは複合クエリではない為、mysql_queryの際にも発生します。

実行されるSQL文は以下のようになり、

select * from geekDB where id = '' OR effective=0

effectiveが0のレコードを取得というSQL文に変わりします。

WHERE句を自由に設定できるということは、そのテーブルのデータを好きなように取得できるということになります。

UNION句

$_GET['id']の値が以下のような場合にもSQLインジェクションが発生します。

'' UNION SELECT * FROM geekDB_secret 

UNIONを利用して他のテーブルのデータと結合して、geekDB 以外のテーブルのデータを取得することも可能です。

このようにmysql_queryの際にもSQLインジェクションは発生しますので忘れずに対策する必要があります。

mysql_real_escape_stringを過信しない

SQLインジェクションについてmysql_real_escape_stringを利用するのは定石ですが、正しく使わないとSQLインジェクションは防げません。

$sql="select * from geekDB where id = " . mysql_real_escape_string($_GET['id']);
$result = mysql_query($sql); 

このコードにはまだSQLインジェクションの脆弱性が含まれています。
というかほとんど改善されていません

$_GET['id']が以下のようなSQLの場合、結局WHERE句を自由に変更することが可能です。

1 OR effective=0

mysql_real_escape_stringがエスケープする文字は『\x00』、『\』、『'』、『"』、『\n』、『\r』、『\x1a』なので、なにもエスケープされずにクエリを実行することが可能です。

$sql="select * from geekDB where id = '" . mysql_real_escape_string($_GET['id'])."'";
$result = mysql_query($sql);

数値などのデータでもWHERE句などに入れる際には'(シングルクオーテーション)で包むことで対策することが可能です。

以下のサイトも合わせてごらんになるとよいかなと思います。

SET NAMESは禁止
PHP の extract 関数は危険という話
HelloWorldプラスアルファからさらに上を目指すために

関連エントリー

PHPサイバーテロの技法―攻撃と防御の実際
re:キケンなSQLインジェクション
絶対に公開してはいけないPHPプログラミング
ふつうのリロード対策
WEBデザイナーの為のXSS(クロスサイトスクリプティング)入門

スポンサードリンク

«10月のセミナー案内 | メイン | CSS Nite in Osaka vol.12終了»