SQLのバインド機構は「エスケープ処理された値」をはめ込むのか

以前このブログでも取り上げたことのある神戸デジタル・ラボの近藤伸明氏がThink IT上で「SQLインジェクション大全」という連載を執筆しておられる。その第三回「SQLインジェクションの対策」を読んで以下の部分が引っかかった。

バインド機構とは、あらかじめSQL文のひな型を用意し、後から変動個所(プレースホルダ)に実際の値(バインド値)を割り当ててSQL文を生成するデータベースの機能だ。バインド値はエスケープ処理した後にプレースホルダにはめ込むので、悪意あるSQL文が挿入されても、その実行を阻止することができる(図1-2)。

http://thinkit.jp/article/847/1/

 たしかにエスケープ処理を使ってバインド機構を実装する場合もある。JavaとMySQLの組み合わせでUnicodeのU+00A5を用いたSQLインジェクションの可能性 | 徳丸浩の日記から派生して、MySQL+JDBCの組み合わせでは、デフォルトではPreparedStatmentとしてクライアント・サイドのプリペアードステートメントが使われることが分かった。このあたりの話題はConnector/J 5.1とServer Side Prepared Statement - mir the developerが詳しい。そちらをお読みいただくとして、クライアント・サイドのプリペアードステートメントとしてバインド機構を実装している場合は、先に引用したように、「バインド値はエスケープ処理した後にプレースホルダに」埋め込まれる。
 しかし、このような挙動は私の期待とは異なるし、私の周囲のブックマークやwassr.jpの書き込みなどを見ても、「バインド機構はサーバーサイドのプリペアードステートメントを使うもの」という意識の方が多かったように思う。
 サーバーサイドのプリペアードステートメントの場合は、エスケープ処理は行われない。その代わり、プレースホルダ記号が置かれたままのSQL文とバインド値が個別にサーバー側に送られる。サーバー側ではSQL文を構文解析するが、その際にキャッシュの内容を確認して、既にキャッシュされたものであれば、構文解析処理を省略してキャッシュの方を利用する。このあたりの解説とメリットについてはJDBC接続を高速化する− PreparedStatementキャッシュの威力−:事例に学ぶWebシステム開発のワンポイント(11) - @ITが分かりやすい。すなわち、サーバーサイドのプリペアードステートメントを使うと、以下のようなメリットがある。

 SQLインジェクション対策には大きくバインド機構とエスケープの2種類の方法があるが、第1選択肢としてバインド機構が推奨される理由は、この「原理的にSQLインジェクションの可能性がない」ことによるものだと考える。つまり、サーバーサイドでないとその意味がない。その至近の例として、先に参照した「U+00A5によるSQLインジェクション」についても、クライアント・サイドのプリペアードステートメントでは脆弱性の可能性があり、サーバーサイドのプリペアードステートメントでは問題がなかった。このため、引用した「エスケープ処理した後にプレースホルダに」という部分に引っかかったわけだ。

 ところで、バインド機構の説明は他の文献ではどうなっているのだろうか。日本で一番権威のある「安全なウェブサイトの作り方 改訂第3版」について調べてみた(同書P7)。

1)-1 SQL 文の組み立てにバインド機構を使用する
解説
これは、SQL 文が注入される原因を作らない実装です。バインド機構とは、実際の値がまだ割り当てられていない記号文字(プレースホルダ)を使用してあらかじめSQL 文の雛形を用意し、後に実際の値(バインド値)を割り当ててSQL 文を完成させる、データベースの機能です。バインド値はエスケープ処理されてプレースホルダにはめ込まれるため、利用者に入力された悪意あるSQL 文の実行を防ぐことができます。

http://www.ipa.go.jp/security/vuln/websecurity.html

 意外なことに、「安全なウェブサイトの作り方」でもエスケープ処理云々という記述がある。もう一つ興味深いことに、先に引用したThink ITの引用部分と酷似しているというか、少なくともかなり似ている。Think ITの解説末尾では【参考文献】として安全なウェブサイトの作り方を参照しているので、悪意的なものではないにしても、誤解を招きやすい行為とは言えるだろう。ここまで似てしまうのであれば、いっそ引用してしまえばよかったと思う。
 では、類似の内容は他所にはないのか。簡単に調べてみた。以下の二カ所が見つかった。

SQLインジェクションSQL Injection)の対策

(2)バインド機構の使用
・バインド機構とは、あらかじめSQL 文の雛形を用意し、後から変動箇所(プレースホルダ)に実際の値(バインド値)を割り当ててSQL 文を生成するデータベースの機能です。
・バインド値はエスケープ処理した後にプレースホルダにはめ込むので、悪意あるSQL 文が挿入されても、その実行を阻止することができます。

参考文献:IPA:安全なウェブサイトの作り方

http://column.proactivedefense.jp/topics/2008/03/sqlsql-injection.html

バインド機構(バインドメカニズム)とは、あらかじめSQL文のひな形を定義しておき、プレースホルダーを使うことで実際の値を割り当ててSQL文を完成させる、という仕組みです。プレースホルダーに値が入るときには、SQL文の組み立てに必要なエスケープ処理が行われるので、悪意のあるSQL文の組み立てを防ぐことができます。そのためSQLインジェクション対策として利用することが推奨されています。

http://脆弱性診断.jp/words/w-sql/data/000059.html

 脆弱性診断.jpの方は、「安全なウェブサイトの作り方」を参照していないので、より紛らわしい行為ということができるかもしれない。

 結論はこうだ。

  • 「安全なウェブサイトの作り方」に示されているバインド機構の説明は必ずしも正確ではない
  • その正確でない説明が劣化コピーされてばらまかれている
  • IPAが公表している文書でも特記されていない限り著作権がある。引用など基本的なルールを守ろう

参考:WASForum Conference 2008講演資料「SQLインジェクション対策再考」