パスワードを忘れた? アカウント作成
522075 journal

TarZの日記: なぜSQLインジェクション脆弱性は減らないのか 3

日記 by TarZ

 SQLインジェクション脆弱性が話題になることがずいぶん増えた。

 従来のC/Sアプリケーションでも同じ問題を抱えていたが、不特定多数から使われうるWebアプリでは特に危険が高い。SQLインジェクションによるアタックがニュースになるのは、ほぼ全てWebアプリの脆弱性としてだ。これについて、ちょうど関連する記事が出た。

SQLインジェクション攻撃が激増 (ITmedia)

 SQLインジェクションについては、採るべき対策はずいぶん前から言われ続けている。しかし、いつまでたっても脆弱性を抱えたシステムは減らない。

 これについてはずっとモヤモヤしていたものを感じていた。ちょうどよい機会なので、忘れないうちにモヤモヤを形にしておく。

(註) ここにまとめているのは根本原因の推測のメモであって、SQLインジェクションに対するなんらかの具体的方策を提起するものではありません。考察の誤りや事実誤認があればコメントでツッコミをお願いします。

… … … …

 SQLインジェクションは、「文字を扱うデータ操作を、文字を組み立てた文で行う」というSQLの宿命だ。
 データであるべき領域と命令である部分が、シングルクォートという薄皮一枚を隔てて混在している。その境界は(人間にとっては)曖昧で、複雑で長いSQLでは(プログラム上での文字列結合、特殊文字のエスケープなども含めると)直感では解りにくい。

 多くの事例は、パラメタライズドクエリ(変数バインディング)を使えば回避できる。しかし、WHERE句に任意個数の条件を付与したり、LIKE句を使う場合のように、パラメタ化だけでは脆弱性対策とならないケースもある。この場合はやはりSQLに動的な文字列を埋め込むことになり、必要に応じてエスケープしなければならない。

 高木浩光氏のサニタイズ言うなキャンペーンでは、エスケープ処理について次のように書かれている。

正しいSQLインジェクション対策は、文字列連結でSQL文を構成しようとする全ての箇所で、「'」で括った部分に埋め込む式の値に対して「'」のエスケープ処理を施すというものだ。それを淡々と遂行していればこのようなことにはならない。
(中略)
すべての箇所でエスケープするのが元々当然なのであり、当然だということを伝えるべきである。

 全くその通り。ただそれだけのことなのに、なぜ脆弱性を持つシステムが減らないのだろう。または、なぜ明らかに誤った対策指南が多いのだろう。

 おそらくは、「そもそもエスケープ処理は難しいから」だ。別の言い方をするなら、「本来のビジネスロジックとは無関係で」「プログラマの直感に反した処理だから」。

 高木氏の対策は指針としてはよいが、実際の業務で作りこむ場合、ここに書かれている情報だけでは不足だ。
 前述のように、ケースによっては ' 以外の特殊文字、例えば _ や % もエスケープ処理する必要がある。これらが正しくエスケープされない場合、例えば更新や削除クエリのLIKE句にこれらを埋め込まれると、意図しないデータ改変が走ってしまう可能性がある。(更新削除でLIKE句を使うことの是非は置いておく。通常はこんなことはしない)
 さらに、エスケープすべき特殊文字ははDBMSによって異なる。例えば MS SQL server なら、[ や ^ も対象になる。とても「淡々と処理すれば」済むものではない。(後述※1)

 Webアプリの分野に限っても、セキュアなプログラミングのために考慮すべき項目(というものが、私の勤務先にはある)は膨大だ。SQLインジェクション対策の項目は、そのうちのごく一部に過ぎない。しかも、チェック項目を全て守ったところで、全ての問題をカバーできるわけではない。(あくまで指針に過ぎない)
 私は教育に携わったこともあるが、全てのプログラマやテスタにこれを徹底させるのは不可能だと感じている。現実問題として、これだけプログラムが大規模・複雑になっている昨今では、プログラマの能力やテストに頼った対策は難しいと言わざるを得ない。開発に携わる全プログラマを高スキル者にすることはできないし、テストをすり抜ける脆弱性は必ず出てくる。

 「淡々と正しくプログラムを組めば」というのは当然の要求だ。しかし、その要求レベルは、大多数のプログラマの能力を超えないものでなければならない。そして、大多数のプログラマは必ずしも向上心に満ち溢れ、情報収集に努めている人ばかりではないということ、高スキル者はごく一部に過ぎないことを前提にしなければならない。
 例えば、「正しくプログラムを組めばバッファオーバーフロー脆弱性は防げる」のは正しい。ただし、それを全てのプログラマが実践するのは困難だという前提のうえで対策されねばならない。「(C言語で)外部から入力されるデータに対してstrcpyといった関数を使ってはならない」という古典的ルールを並べても、それはバッファオーバーフローの根絶には至らなかった。プロセッサにNXビットによる保護機構を追加したり、Cのようなシンプルな処理系からJavaといった安全なデータ管理機構を持つ処理系にシフトすることで、ようやく単純なバッファオーバーフローに伴う脆弱性は減りつつある。(と、私は感じている。そうでもないのかもしれないが)

 SQLは、プログラミング言語からDB問合せを切り離す優れた方法だった。使っている言語がCだろうとJavaだろうと、SQLで問合せができた。これを別の何かに置き換えていくのは容易な仕事ではない。しかし、いまやSQLに代わるものが必要だと思う。
 高木氏も理事として参画しているWeb Application Securityフォーラムで、SQL-Injection Defense Tree (PDF)という資料が公開されている。分かりやすくて適度に短く、優れた資料だと思う。ここで言われるところの「2.1.2. DBIレイヤの抽象化」が、私が理想と考える対策に近い。
 資料にあるように、DBIレイヤを抽象化するフレームワークを使う。あるいは、プロジェクトで個別に作る場合は、その部分は対象DBMSを熟知した高スキル者のみで書き、一般のプログラマに直接SQLを扱わせない。資料に書かれている対策のうち、真に有効となるえるのは、おそらくこの方法だけだろう。

 問題は、この方法はSQLと違って言語やフレームワークに依存しており、標準化されていないことだ。つまり、DBIレイヤの抽象化による対策は、それを盛り込んだシステムでは根本対策となりうるものの、Webアプリケーション界全体としてみれば散発的・局所的なものになりがちだ。数年内に、この分野でなにか大きな進展があるとも思えない。
 結局のところ、まだしばらくはSQLインジェクションによる脆弱性はなくならないだろう。

… … … …

(※1)
 1つ、実際のサイトで例を挙げる。

 .NET向けにAuto Suggest機能のデモを行っているこのサイトは、公開されたソースをみると ' のみエスケープしている。
 この例ではアルファベットの都市名検索のみの機能なので、これが直ちにセキュリティホールにはならないが、_ や % を使うと(SQLを知らない使用者にとって)意図しない結果を返す。仮に、検索対象となる都市名に _ を含むものがあったなら、正しく絞り込めない。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2006年07月22日 0時15分 (#982457)
    Javaではプリペアドステートメントさえ使っていれば、
    基本的に入力時にエスケープを網羅する必要はありません。
    (クラスに既知のバグは無く、サーバは適切にパッチが当てられている前提で)

    結果を画面時に出すときには必要ですが。

    >そもそもエスケープ処理は難しいから
    という事よりも、納期延期に対してセキュリティ対策が理由にならず、
    費用対効果を安く見積もられているからにすぎないと思います。
    そして、開発を2つ3つ抱えた環境で、セキュアなロジックを
    共通化してない人の出入り、業者の出入りが激しい現場、
    低コストを求めて監査もいれず安易にオフショア丸投げの現場で起きる。
    と経験からいうとそんな感じです。

    本気で難しいというのは、単に向上心のないメンバーが集まって、
    何も現場に蓄積する事なく去っていく所だと思います。
    • by Anonymous Coward
      今、店頭に出ている号に、Javaのプリペアドステートメントでも
      脆弱性が発生するケースとか言うコラムが出ているが、
      差込み元SQLの組み方というか、プリペアドステートメントの使い方を、
      激しく間違えている訳で、そんな事して「脆弱性が出る場合がある」
      とか抜かすレベルの人間が本を書いているんだなと。

      これは歴史的資料になると思うので、買っておいて損は無いでしょうワラ
      該当記事:Javaデータアクセス優先主義/松信嘉範 [seshop.com]
  • by Anonymous Coward on 2006年08月08日 22時41分 (#993308)
    そのような場合には、JavaではDynamic Query(QL) [google.co.jp]とか使うとスマート。
    日本語だと、まだ利用例が少ない [seesaa.net]し、何より環境依存だけど。
    セキュリティのために環境を選ぶ、環境からセキュリティを構築する、
    (もちろん○○入れたから対策OKと思わないのは大前提)
    というのはデフォルトになっていくかもしれません。
    というか、そうでないと忘れた頃に酷い被害を出す繰り返しのような。

    たとえば、セキュリティ対策のリファレンス実装が存在していて、
    ウイルスのパターンファイルみたいに更新されて無料、
    そういう言語でないと、にわかプログラマはWeb上に
    アプリを構築してはいけないとか、野良言語として免許を要するとか。
    PHPなんて、にわかプログラマではいくらやっても一寸先は闇だ。
    (PHPに罪があるというよりも、簡易さにおいて優れており、
    便利であるため多くの素人さんが手を出すため狙われるのかも)
typodupeerror

UNIXはシンプルである。必要なのはそのシンプルさを理解する素質だけである -- Dennis Ritchie

読み込み中...