注意!この記事は「安全なSQLの呼び出し方」を読んで、自分なりに解釈したものになる。
セキュリティについて勉強したい人は「安全なSQLの呼び出し方」を読むほうがいいよ。
前回は、リテラルとSQLインジェクション(安全なSQLの呼び出し方)でリテラルについて学んだ。
SQLインジェクションがどのように起こるのかも。
今回は、実際の SQLの呼び出し方について学ぼう。
アプリケーション側から検索条件などの数値をパラメータとして渡す方法には2つある。
・文字列連結によるSQL文の組み立て
・プレースホルダによるSQL文の組み立て
1.文字列連結によるSQL文の組み立て
文字列連結による組み立てとは、アプリケーションのプログラミング言語で、SQL文を生成するとき、パラメータ部分への値の埋め込みを文字列連結によって実現する方法です。
文章で説明されてもイメージわかない。
パラメータ「name」に指定された社員を検索するSQL文を、PHPで組み立てる処理の例が以下。
$name = $_POST['name']; //... $sql = "SELECT * FROM employee WHERE name='" . $name . "'";
$nameが「山田」なら以下のSQL文が生成される。
SELECT * FROM employee WHERE name=’山田’
しかし、このプログラム(SQL文のことじゃないよ)だと、SQLインジェクションの脆弱性がある。
$nameをエスケープ処理しなければならない。
PHPだと「mysql_real_escape_string」を使えばいいのかな。
以下のように変更。
$name = $_POST['name']; //... $sql = "SELECT * FROM employee WHERE name='" . mysql_real_escape_string($name) . "'";
2.プレースホルダによるSQL文の組み立て
プレースホルダによる組み立てとは、パラメータ部分を「?」などの記号で示しておき、後に、そこへ実際の値を機械的な処理で割り当てる方法です。
「安全なSQLの呼び出し方」のサンプルが Javaだった・・・
セキュリティの鬼たるはまちちゃんのブログ記事から引用させてもらいます。
$sth = $mdb2->prepare('SELECT name FROM users WHERE id=?'); $res = $sth->execute($data);
ここで、パラメータ部分を示す記号「?」のことをプレースホルダと呼ぶ(1行目)。
そこへ実際の値を割り当てることを「バインドする」と呼ぶ(2行目)。
プレースホルダのことを「バインド変数」と呼ぶこともある。
このプレースホルダは、バインドをいつ行なうのかによって2種類に分けられる。
・静的プレースホルダ
・動的プレースホルダ
静的プレースホルダ
静的プレースホルダは、JIS/ISOの規格では「準備された文(Prepared Statement)」と規定されています。これは、プレースホルダのままのSQL文をデータベースエンジン側にあらかじめ送信して、実行前に、SQL文の構文解析などの準備をしておく方式です。SQL実行の段階で、実際のパラメータの値をデータベースエンジン側に送信し、データベースエンジン側がバインド処理します。
バインドのタイミングがDB側の場合を、静的プレースホルダと呼ぶ。
実行効率とセキュリティの観点から見てみる。
実行効率:同じSQL文をパラメータのみ変えて繰り返す場合に、構文解析を事前に済ましておくことで、実行効率を高くできる。
セキュリティ:SQL分の構文が事前に確定することから、プレースホルダに渡す文字列はクォートやエスケープ処理をしなくてもよく、最も安全なSQLインジェクション対策といえる。
動的プレースホルダ
動的プレースホルダは準備された文(Prepared Statement)とは異なり、プレースホルダを利用するものの、パラメータのバインド処理をデータベースエンジン側で行うのではなく、アプリケーション側のライブラリ内で実行する方式です。
バインドのタイミングがアプリケーション側の場合を、動的プレースホルダと呼ぶ。
実行効率とセキュリティの観点から見てみる。
実行効率:パラメータをバインドしたSQL文をデータベースへ送るため、実行効率では静的プレースホルダに劣る。
セキュリティ:パラメータの値の埋め込みはライブラリにて機械的に処理されるため、「文字列連結」よりはセキュリティは高い(エスケープ漏れなど)。ただし、静的プレースホルダに比べると、バインド処理を行なうライブラリのバグを否定しきれないため、低い。
3.まとめ
まとめると、優先順位はこんな感じとのこと。
静的プレースホルダ > 動的プレースホルダ > 文字列連結
ただ、これらの議論は色々されているっぽい。
古いPHPなんか使ってるとプレースホルダとか使えないかもしれないしね。
PHPとDB関係はここがとても詳しい。
勉強、勉強。
コメント