2009年3月27日金曜日

JETエンジンにおいてパイプ記号「|」は今でも「危険」なのか

補足

この記事は旧徳丸浩の日記からの転載です(元URLアーカイブはてなブックマーク)。
備忘のため転載いたしますが、この記事は2009年3月27日に公開されたもので、当時の徳丸の考えを示すものを、基本的に内容を変更せずにそのまま転載するものです。
補足終わり

SQLインジェクション対策の続きで、セキュア・プログラミング講座には、2種類の文字を不受理にせよと書いてある。「;」(セミコロン)と「|」(パイプ記号)だ。

このうち、セミコロンについては不受理にする必要はなく、はっきり間違いといってよいだろう。『3)セミコロン「;」の拒否』の項ではセミコロンを用いた攻撃例も出ているが、脆弱性の原因はセミコロンではなく、シングルクォートをエスケープしていないところにある。バインド機構を用いるか、シングルクォートをエスケープすれば、セミコロンを恐れる必要は全くない。それに、複文を用いた攻撃をもっとも受けやすいMS SQL Serverの場合は、セミコロンなしでも複文を記述できることは前述した。すなわち、原理的にも、現実的にもセミコロンの拒否は意味がない。

一方パイプ記号の方はどうだろうか。少し長いが該当箇所を引用する。
5) その他の特殊記号への対処(Microsoft Jetエンジン)
またMicrosoftのJetエンジンでは、次の文字も機能をもつ特殊記号として扱われる。
  |  VBAステートメント実行文字
Jetエンジンは,与えられたSQL文の文字列の中に「|...|」で囲まれた部分があると、それをVBA(アプリケーション用のVisual Basicサブセット言語)のステートメントとして解釈し実行する。
 これは、SQL 文の中の「'...'」で囲まれた文字列の中に書かれていても起こる。
 これを悪用すると外部からの任意のシステムコマンドの投入が可能となり、最悪の場合、システムが乗っ取られるおそれがある。
このパイプ記号「|」をエスケープする方法は提供されていないため、パイプ記号「|」が含まれている入力パラメータは受理しないようにする必要がある。
  | → 受理しない
Jetエンジンは、Microsoft Accessのデータベースエンジンであるが、直接Access を利用しているつもりがなくても、拡張子「.MDB」をもつデータベースファイルにアクセスする際に使われることになるので注意が必要である。
[SQL組み立て時の引数チェック(アーカイブ)より引用]
この内容は他の文書類ではあまり見かけない。また、私はACCESSおよびJetエンジンの実務での開発経験がなく、また脆弱性診断などでもお目に掛からないので、今までこの問題を検証しないできたのだが、念のため確認してみた。

この問題に言及している文書としては、2000年2月に塩月誠人氏が公開された「セキュリティ勧告 - NTサーバ上におけるJetセキュリティ問題」がある。
Windows NT上で稼動する、MS Accessデータベース(mdbファイル)にアクセスするようなサーバプログラムは、Jetセキュリティ問題(いわゆる Office ODBCドライバ問題)の影響を受ける可能性がある。このセキュリティ問題の影響を受けるサーバプログラムに対し、悪意を持ったユーザが不正な入力を行なうことにより、サーバマシン上で任意のコマンドが起動する危険性が生じる。
[セキュリティ勧告 - NTサーバ上におけるJetセキュリティ問題より引用]
脆弱なサンプルと検証用文字列は以下のようになっている。

脆弱なサンプル:
  set db=Server.CreateObject("ADODB.Connection")
  db.Open "btcustmr"
  sql="select * from Customers where City='" & word & "'"
  set rs=db.Execute(sql)>
検証用文字列:
  |shell("cmd /c echo aaa > c:\test.txt")|   (注: "|" は縦棒文字)
手元のWindows Server 2003を用いて、上記を検証してみたが再現しなかった。パイプ記号は特に不都合なく挿入も検索もできる。塩月氏のレポートから9年も経っているので、Microsoft社が対策したのだろうか。試しにAccess 2003を当該Windows Serverに導入してみたが、現象は変わらなかった(TechNet Plus サブスクリプションを使用)。また、Access 2000 および Access 2002 で、安全でない関数が実行されないように Jet 4.0 を構成する方法などを参考にレジストリをいじったりしたが、やはり現象は再現しない。

このように、現在の環境では「Jetセキュリティ問題」を再現するのは難しいようだが、過去このような問題があったことは確実なので、現在においても「いかなる環境でも絶対に安全」とは断言できない。このような状況下でセキュリティコンサルタントとしてどのようにアドバイスすべきだろうか。

私がJetエンジンを今まで無視してきた理由は、同時に多数が利用するWebアプリケーション構築にJetのようなファイル共有タイプのデータベースエンジンを使用するのは好ましくないと考えるからだ。その方向で技術資料を探してみると、ぴったりそのままの文書が見つかった。
しかし Access ODBC ドライバ、および OLE DB Provider for Jet は、Web システムなどの多くのユーザーからのアクセスによる同時実行や高負荷の対応はされておらず、また、終日稼動で運用されるような高い信頼性を要求されるサーバー アプリケーションで使用されることを考慮して設計されていません。そのため、この様なシステムの場合、弊社では IIS/ASP と共に Microsoft SQL Server、または Microsoft Desktop Engine (以下 MSDE) 等のセキュリティ、常時運用の可用性・信頼性、および拡張性を備えたデータベースの使用を推奨しています。
[IIS 上での Jet データベース エンジンの使用について より引用]
上記のようにMicrosoft自身がWebシステムでのJetの使用を推奨していないのだ。そして、以下の内容が続く。
しかし、Access ODBC ドライバはスレッド セーフではないため、複数のユーザーが同時に MDB ファイル (Access データベース) に要求を行うと、予期せぬ動作が引き起こされる場合があり、システムの安定性に影響を及ぼす可能性があります。そのため、安定性、パフォーマンス、およびスレッド プーリングに対する修正および機能強化を含んでいる OLE DB Provider for Jet の使用を弊社では推奨しています。
注意 : OLE DB Provider for Jet はスレッド セーフですが、Jet がスレッドセーフでないため、完全なマルチ スレッド環境を実装することはできません。そのため、OLE DB Provider for Jet を使用した場合でも、応答がなくなるなど予期せぬ動作が引き起こされる可能性があります。
[IIS 上での Jet データベース エンジンの使用について より引用]
色々書いてあるが、「Jet がスレッドセーフでない」という箇所が重要だ。このことから、Jetを使用したWebアプリケーションでは「別人問題」のように、他ユーザの情報が漏洩する可能性などが考えられる。

まとめよう。「Jetセキュリティ問題」は過去の問題とは言い切れないかもしれないが、少なくとも現在では非常にトリビア的な問題だ。しかも、JetをWebシステムでは使うべきでないとMicrosoft自身が明記しているのだ。であれば、セキュア・プログラミング講座で説明すべきことは、「パイプ記号を受理しない」ではなく、こうだろう。

  例えば、Jetエンジンを避ける

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

2009年6月16日追記

本エントリを書いた後、セキュアプログラミング講座の内容は大きく改訂されたようで、ここで指摘した問題はすべて解消されている。関係者の皆様、ありがとうございました。

0 件のコメント:

コメントを投稿

フォロワー

ブログ アーカイブ