何この記事
その名の通り備忘録。
みんなが知っているSQLインジェクション対策で同じように間違えないように、、、
短い本編
初心者と経験者と分けて説明します。
今回使うテーブルにはサザエさん一家を使います。
テーブル名:Family
ID | Name |
---|---|
1 | フグ田サザエ |
2 | 磯野波平 |
3 | 磯野フネ |
4 | フグ田マスオ |
5 | 磯野カツオ |
6 | フグ田タラオ |
7 | 磯野ワカメ |
8 | タマ |
初心者
PHP触りたてほやほやの人が書きそうな文
$ID = 1;
$sql = "SELECT*FROM `Family` WHERE ID = '" . $ID . "';";
$stmt = $dbh->query($sql);
おや?SQL文が簡単そうですね。では、実行してみましょう。
結果
ID | Name |
---|---|
1 | フグ田サザエ |
IDが1の人がヒットしました。さて、皆さんはお気づきかもしれませんが、この文では攻撃が簡単にされてしまうんです。
では、攻撃をしてみましょうw
$sql = "SELECT*FROM `Family` WHERE ID = '" . $_GET['format'] . "';";
$stmt = $dbh->query($sql);
先ほどの$ID
を消してGET関数で取得してみましょう。
この時に攻撃を仕掛けます。
https://exsample.com?format=1; DROP TABLE Family
結果
ID | Name |
---|---|
1 | フグ田サザエ |
Q. あれ攻撃できたのかな?
A. 出来てます。(ΦωΦ)
PHPMyAdminでテーブルを確認すると、
. . . テーブルがない。( ;∀;)
サザエ一家がお亡くなりになった?!
説明すると、SELECTした後にDROPしたのでテーブルがなくなる仕組みになっています。
じゃあどうすればいいのさ!初心者は考えました。
妄想↓
変数の空白をなくせばいいんじゃね?
でも、Blog投稿とかしたいのに空白なくすのは嫌だなー。
初心者:諦めるか!
経験者:PHPに愛はあるんか!
初心者:あるっちゃある . . .
経験者:なら、我についてこい!
おっと、経験者が何か答えを出してくれるそうです。
経験者
攻撃されやすい書き方
$sql = "SELECT*FROM `Family` WHERE ID = '" . $_GET['format'] . "';";
$stmt = $dbh->query($sql);
攻撃されにくい書き方
数値を入れたい場合
$sql = "SELECT*FROM `Family` WHERE ID = :ID ;";
$sql->bindValue(':ID', 1, PDO::PARAM_INT);
$sql->execute();
文字列を入れたい場合
$sql = "SELECT*FROM `Family` WHERE Name = :Name ;";
$sql->bindValue(':Name', 'フグ田サザエ', PDO::PARAM_STR);
$sql->execute();
さて、違いがわかると思いますが、bindValue()
とPDO::
を使って実行文ではなく普通の文字列または数値として扱ってくれます。あら、うれしいわ♡
ふつうに関数も
$sql->bindValue(':Name', $_GET['format'], PDO::PARAM_STR);
として入れることができます。
まとめ
最初は文字列を結合して実行文を完成させるということで実行していました。しかし、これでは攻撃されやすいので、文字列として受け入れるようにしました。
みなさんも、攻撃には気を付けてください。(ΦωΦ)