11. プレースホルダ
よくない例
●
my $dbh = DBI->connect(...);
my $sql = "SELECT id, name FROM employee WHERE id = $id";
my $sth = $dbh->prepare($sql);
$sth->execute();
変数をそのまま SQL 中に
埋め込むのはダメ!
12. プレースホルダ
なぜ良くないか
●
●
セキュリティ
●
$id が外部からくる値(たとえばフォームの入力)の場合、
どんな値が渡されるか分からない
●
たとえば「0 OR 1=1」のような値が渡されると、テーブ
ルの情報をすべて抜かれてしまう
●
SQLインジェクション
●
他のテーブルに何かされたり、データを盗まれたり、
破壊される場合も
my $dbh = DBI->connect(...);
my $sql = "SELECT id, name FROM employee WHERE id = $id";
my $sth = $dbh->prepare($sql);
$sth->execute();
13. プレースホルダ
文字列化?(サニタイズ?)
●
my $sql = "SELECT id, name FROM employee WHERE id = '$id'";
●
SQL の変数部分を文字列化して、この問題を防ごうとする
のは止めましょう
●
数値型に文字列を渡すと、インデックスが効かなくなるこ
とがある(遅くなる。逆の場合も同じ)
●
たとえば「' OR 1=1 --」という入力を渡すとこの場合も
全件出力されてしまう(無意味)
14. プレースホルダ ? がプレースホルダです
解決策:プレースホルダ
●
my $dbh = DBI->connect(...);
my $sql = "SELECT id, name FROM employee WHERE id = ?";
my $sth = $dbh->prepare($sql);
$sth->execute($id);
SQL で「?」で指定した値をここで渡す
●
先ほどの怪しい入力を渡すとエラーになる
●
型のミスマッチで遅くなることが無い
●
使い方もそんなに難しくない
22. SQLを見たい!
みんな大好きコンビ print デバッグ & Data::Dumper
●
my $dbh = DBI->connect(...);
my $sql = "SELECT id, name FROM detective WHERE id = ?";
use Data::Dumper; warn Dumper($sql, @binds);
my $sth = $dbh->prepare($sql);
$sth->execute(@binds);
●
手軽
●
問題となってる SQL の場所が分かっている場合はある程度
有効
●
bind されている値は見づらい
●
bind 変数がずれてるとか、そういった問題は見つけにく
い
23. SQLを見たい!
$DBI::trace 変数
●
$ env DBI_TRACE=1 perl a.pl
DBI 1.620-nothread default trace level set to 0x0/1 (pid
28328 pi 0) at DBI.pm line 276 via a.pl line 5
...
<- prepare('SELECT id, name FROM detective WHERE id
= ?')= ( DBI::st=HASH(0x15a13d8) ) [1 items] at a.pl line 11
<- execute('1234')= ( '0E0' ) [1 items] at a.pl line 12
...