問題の提起

例のITproへの連載では、インジェクション系の脆弱性を取り上げて、正しい対策について考察してみたが、

はびこる「インジェクション系」のぜい弱性 | 日経 xTECH(クロステック)
対策遅らせるHTMLエンコーディングの「神話」 | 日経 xTECH(クロステック)
まだまだあるクロスサイト・スクリプティング攻撃法 | 日経 xTECH(クロステック)
インジェクション系攻撃への防御の鉄則 | 日経 xTECH(クロステック)

この中で、高木浩光氏から以下に関する内容についてコメントを頂戴した。

変数に型のない言語(Perl, PHP, Rubyなど)で
数値などシングルクォートでリテラルを囲まない項目に対する
SQLインジェクション

ITproに書いた原稿を少し引用する。

 実装例を挙げて説明しよう。以下のSQL は,掲示板の投稿文書テーブルから,投稿ID(整数型)を指定して文書を削除するものである。言語は,PerlあるいはPHPを想定している。

$sql = "DELETE FROM DOCUMENTS WHERE ID = $id";

 変数$idをシングルクォートで囲っていないことが分かるだろう。ここで,PerlPHPでは変数に型がないために,$idに以下のような文字列を入力することも可能である。

$id = '0 or TRUE'; # 実際には入力欄に「0 or TRUE」を入力

 こうすると,組み立てられるSQLは以下のようになり,すべての投稿を削除できることになる。

DELETE FROM DOCUMENTS WHERE ID = 0 or TRUE

 数値型を想定した変数に文字列を入力することが前提だから,攻撃が成り立つのは,プログラミング言語としてPerlPHPのように変数に型がないものを使っている場合に限られる。ただ,PerlPHPはWebアプリケーション開発に広く利用されているので決して軽視はできない。
【中略】
原因が数値を想定した変数に文字列を入力することにあることから,対策は入力値の妥当性検証である。SQLインジェクション対策以前の問題として,アプリケーション要件を満足する意味でも妥当性検証は必要である。
 このケースは色々と悩ましいところがあって,セキュリティ業界でも定見がないように見受ける。ネット上には,数値型の場合でもシングルクォートで囲ってしまうことを推奨するような解説を見かけるが,筆者は賛同できない。SQL実行のたびに文字型から数値型への暗黙の型変換が行われるのは,性能的にも不利だし,プログラミング書法という点でも望ましくないと考えるからである。

これに対する高木浩光氏のコメントを引用する。

インジェクション系攻撃への防御の鉄則:ITpro
2007年04月26日
[セキュリティ][SQLインジェクション]「性能的にも不利だし」 < 性能の影響は皆無。問題はそこではなく、挙動がSQL仕様で定義されているか。「対策は入力値の妥当性検証」 < それは違う。SQL文構成時直前に型変換(ないし型検査)する。文字列のクオート同様

いまWebアプリ脆弱性対策で、無料で入手できる資料としては、安全なウェブサイトの作り方:IPA 独立行政法人 情報処理推進機構がもっとも信頼できるように思うが、同書にも、このケースについて記述されていない。同書のP6には、

1)-2 バインド機構を使用できない場合は、SQL 文を構成する全ての変数に対しエスケープ処理を行う

とあるが、ここの記述では数値型項目に対するSQLインジェクションを防御できない(変数に型のない言語の場合)。
連載中にも書いたように、この問題は、頻繁に出てくるはずの問題にも関わらず、あまり議論が熟していないように思われる。このため、高木浩光氏のコメントに答える形で、この問題を議論してみよう。

続く