調べるきっかけ
PHPでSQLをセキュアに記述する方法としてprepareステートメントが推奨されているが、なぜなのかがわからず、挙動を調べれば自分なりに納得のいく答えがでるのではないかと思ったため。
調べたコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php // ************************************ // SourceName : prepare.php // Purpose : confirm prepare made SQL // ************************************ // DB Config include '../dbconfig.php'; // Statement $stmt = $dbh->prepare('SELECT * FROM boards.boards WHERE id=:id and name=:name'); // Set Values $id = 3; $name = "名無しさん; Delete from boards.boards"; // Execute $stmt->bindParam(":id", $id, PDO::PARAM_INT); $stmt->bindParam(":name", $name, PDO::PARAM_STR); $result = $stmt->execute(); // Debug $stmt->debugDumpParams(); |
$nameの文字列の途中に;(セミコロン)を付与して処理を終了させて、そのあとにDELETE文を実行させようとした。
1 2 3 4 5 6 |
SQL: [55] SELECT * FROM boards.boards WHERE id=:id and name=:name Sent SQL: [92] SELECT * FROM boards.boards WHERE id=3 and name='名無しさん; Delete from boards.boards' Params: 2 Key: Name: [3] :id paramno=-1 name=[3] ":id" is_param=1 param_type=1 Key: Name: [5] :name paramno=-1 name=[5] ":name" is_param=1 param_type=2 |
「’名無しさん; Delete from boards.boards’」となり、
‘(シングルクウォート)で括られて、;(セミコロン)は無効化されていた。
;の手前で’を付与して、;を有効化しようとしてエスケープした場合。
1 2 3 |
// Set Values $id = 3; $name = "名無しさん\'; Delete from boards.boards"; |
「’名無しさん\\\’」となって、エスケープできませんでした。
1 |
SQL: [92] SELECT * FROM boards.boards WHERE id=3 and name='名無しさん\\\'; Delete |
結果
prepareステートメントを利用すると適切にエスケープされるため、SQLインジェクション対策となる。
コメント