SQLインジェクション対策について
教育的な観点ではなく実務的な観点から、僕の考えをまとめてみる。UTF-8 を利用し、SET NAMES を利用していなくて mysql で、クライアントプリペアドステートメントなケースを想定している。
$foo=$_POST[‘id’];
query(“SELECT * FROM foo WHERE id=$foo”);
のように外部からの文字列をそのまま使用してクエリを組みたてたときに、意図せぬ SQL を発行されてしまう脆弱性のことである。
すべてのパラメータを正しくエスケープするか、プレースホルダを使う。
大体のDBドライバーライブラリにはプレイスホルダーを利用する機能が存在している。
$sth = prepare(“SELECT * FROM foo WHERE id=?”);
$sth.execute($_POST[‘id’])
SQL 自体はリテラルで記述し、その一部後から安全にさしかえられる。
エスケープはたとえば以下のように外部からの入力をエスケープするというものだ。
query(“SELECT * FROM foo WHERE id=” + escape($_POST[‘id’]);
実際、どっちをつかっても脆弱性は対策されるのでどっちでもいい。エスケープをDBの(クライアント|サーバー)サイドライブラリで行うか、アプリケーションでやるかの差にすぎない。
だがしかし、プレイスホルダーが利用可能な場面ではプレイスホルダーを利用する方がよい。
その利点は、コードを見たときに、安全に記述されていることがアキラカであるという点だ。コードレビューの際には、この方式でかかれていない部分のみをチェックすればよくなるので、チェックが簡単になる。記述する人も、「よし、ここは手でくみたてる部分だからしっかり書こう」と身構えるようになるからだ。
サーバーサイドプリペアードステートメントを利用していない場合は以下のようにしてしまえばいい。
$sth = prepare(
‘SELECT * FROM foo WHERE id IN (‘
join(‘,’, (‘?’)x@n)
‘)'
);
$sth.execute(@n);
たとえば phpmyadmin 等をつくったりする場合や USE hogehoge
文をくみたてたりする場合にはプレイスホルダーは使えないので、エスケープする必要がある。そんな時はエスケープするしかない。
だいたいの場合、SQL ライブラリがエスケープ関数を提供してくれているので、それを利用すればよい。
存在しない場合は自前で作らざるを得ないが、ちゃんとしたエスケープ関数を作るのはむずかしい!!! そういう場合は開発元に電話をして作ってくれるようにお願いしてみよう!
できるだけプレイスホルダーを使い、プレイスホルダーを使えないところでは公式のエスケープ関数を使おう。