*「ふっかつのじゅもんがちがいます。」withぬこ このページをアンテナに追加 RSSフィード

はてなRSSで購読 Bloglinesで購読 Google Readerで購読

2010-04-09

[SQLインジェクション対策]Webアプリケーションとかの入門本みたいのを書く人への心からのお願い。

SQLインジェクションについて書くときに以下のメッセージを必ず含めて欲しいです。

なんでこんなことを書くかというと、同僚が献本されてた「プロになるためのWeb技術入門」なる本のSQLインジェクションの項で、SQLインジェクションの対策として以下のように書いてあったからです*1

  • a) 値をバリデーションする
  • b) プリペアドステートメントを使う

ダメです。間違っています。単に間違っているだけでなく救いがたく間違っています。正しいSQLインジェクション対策はこう書くべきです。

  • 単にプリペアドステートメントを使え
  • 文字列結合でSQLを構築するな

イケてない本を書く人はなんで値のバリデーションをプリペアドステートメントよりも先に書くんですか?値のバリデーションは必要ですが、それはプログラムの正常な挙動を担保するためであって、SQLインジェクション対策のためではありません。*2

そもそもSQLインジェクションされる脆弱性というのは、単にマヌケがプリペアドステートメントを使わずに文字列結合でSQLを作るようなバグプログラムを書いたというだけです。SQLインジェクションはクラッカーの巧妙な攻撃手法とかではありません。単なるバグです。対策はプリペアドステートメントを使うことだけです。大事なことなので何回も言いました。詳しく知らない人は上記の「安全なSQLの呼び出し方」を読みましょう。

なお上記の本とは関係ないのですが、"SQLのメタキャラクタを適切にエスケープせよ"というメッセージは、字面だけ見れば正しいのですが、現実的には間違っています。私は10年プログラマをしていますが、Web系でプリペアドステートメントがサポートされていないような環境でプログラムを書けといわれたことは一度たりともありません。だから初心者向けの本では「単にプリペアドステートメントを使え」というメッセージで十分だと思います。

SQLのメタキャラクタを適切にエスケープしてSQLを作らなければならない、作るべき場合というのは、ぱっと思いつくのは以下のような場合です*3

  • あなたが作ったRDBMSにはプリペアドステートメント機構がないのでプリペアドステートメントを実装している
  • あなたが作ったプログラミング言語にはRDBMSへ繋ぐクライアントライブラリの既存の実装がなく、Cで書かれたライブラリを呼び出すこともできない設計なので仕方なく自分で実装している
  • あなたの製品が動く環境は組み込みデバイスなので、既存のRDBMSのクライアントライブラリがコンパイルできず、相当するものを自分で作っている

いずれも初心者が遭遇するような場面ではありません。病的な例外と言ってもいいです。したがって、SQLインジェクションの対策メッセージは、現実的にはこうなります。

「単にプリペアドステートメントを使え」

それ以外のSQLインジェクションの文脈では些末すぎること(バリデーションやエスケープ)が書いてある本は燃やしてもいいのではないかと思います。

2011-11-09 追記

今までもid:ockeghemさんには何度か紹介してもらっていたが、改めて「SQLインジェクション対策」でGoogle検索して上位15記事を検証したという記事で紹介してもらった。

この記事は"SQLインジェクション対策"ではちっとも検索にひっかからないようなので、タイトルにそういう文字列を入れた。

*1:セキュリティの章の記述がすごく残念な感じだったので、Amazonへのリンクとかは貼らないことにします

*2:不正な文字エンコーディングによる文字コードSQLインジェクションへの対策として、プログラマが文字コードのバリデーションをしなければならない処理系は存在しますが、この場合でも主客が逆で、まずはプリペアドステートメントであるべきです

*3:あとO/Rマッパーを書く場合というのもあるのだけど、話がそれるので略します