セキュリティに関するブリーフィング
Web アプリケーション構成セキュリティ再考
Bryan Sullivan
数年前 (マイクロソフトおよびセキュリティ開発ライフサイクル (SDL) チームに来る前のことです)、私は、安全でない web.config 設定の危険性に関する記事を執筆し、最も問題となるものトップ 10 を挙げました。この記事は現在もご覧いただけます。お好きな検索エンジンで "Top 10 Application Security Vulnerabilities in Web.Config Files" を検索してみてください。私が当時説明した構成の脆弱性は、現在でも依然として深刻な問題ですが、おそらく、MSDN マガジンを定期的に読んでいらっしゃる方にとっては、それほど驚くような内容ではないでしょう。カスタム エラーを有効にすることは今でも重要です。アプリケーションを運用環境に展開する前にトレースとデバッグを無効にすることは今でも重要です。また、認証 Cookie に SSL を必須とすることは今でも重要です。
今月のコラムでは、当時の記事の続きから始めて、その記事で取り上げた問題に比べると目立たないとはいえ同じくらい深刻なセキュリティ上の構成ミスのいくつかについて説明します。また、マイクロソフト情報セキュリティツール チームが提供する、このような問題を見つけるのに役立つ Web Application Configuration Analyzer と呼ばれる新しい無償ツールについても見ていきます。どんなに安全にコーディングされた ASP.NET アプリケーションでも、適切に構成されていなければハッキングされる可能性があることを忘れないでください。
EnableEventValidation
開発者が比較的よく犯すミスの 1 つは、ユーザーに選択肢のリストを提供し、ユーザーが選択肢として提供された値のいずれかを実際に選択することを想定するというものです。これは十分理にかなっているように思えます。ページに ListBox コントロールを追加し、このコントロールに米国のすべての州をあらかじめ設定しておいた場合、"ワシントン"、"ジョージア"、"テキサス" などが返されることを予想し、"Foo"、"!@#$%"、"<script>alert(document.cookie);</script>" などが返されることは予想しないでしょう。アプリケーションを従来の方法で (つまり、ブラウザーから) 使用してこのような値を指定する方法はないかもしれませんが、ブラウザーをまったく使用せずに Web アプリケーションにアクセスする方法はたくさんあります。Eric Lawrence の Fiddler (これは今でも、Web アプリケーションのセキュリティ上の脆弱性を見つけるツールの中で私が気に入っているものの 1 つで、fiddler2.com (英語) からダウンロードできます) などの Web プロキシ ツールを使用すると、どのようなフォーム フィールドにどのような値を送信することもできます。この可能性に対応できるようになっていないアプリケーションは、危険性を秘めた形で失敗する可能性があります。
EnableEventValidation という構成設定は、この種の攻撃を防ぐのに役立つ徹底的な防御のメカニズムです。悪意のあるユーザーが、限られた一連の値を受け取るコントロール (もともとどのような値でも受け取ることができる TextBox などではなく、ListBox など) に対して、予期せぬ値を送信しようとした場合、アプリケーションは改ざんを検出し、例外をスローします。
悪い:
<configuration>
<system.web>
<pages enableEventValidation="false"/>
良い:
<configuration>
<system.web>
<pages enableEventValidation="true"/>
PasswordFormat
ASP.NET の一部として (ASP.NET 2.0 から) 提供されるメンバーシップ プロバイダー フレームワークは、開発者がメンバーシップ機能のメカニズムを何度も新たに考案しなくて済むようにする優れた機能です。一般に、組み込みのプロバイダーは、既定の設定のままであれば、セキュリティの観点から見てかなり安全です。ただし、メンバーシップの構成設定が変更された場合、こうしたプロバイダーのセキュリティは、大幅に低下することがあります。
この良い例の 1 つは、PasswordFormat の設定です。これは、ユーザー パスワードの格納方法を決定する設定です。Clear (パスワードをプレーンテキストで格納する)、Encrypted (パスワードを格納前に暗号化する)、Hashed (パスワード自体の代わりにパスワードのハッシュを格納する) の 3 つの選択肢があります。この 3 つの中で、Clear が最も悪い選択肢なのは明らかです。パスワードをプレーンテキストで格納するのは常に不適切です。はるかに良い選択肢は Encrypted で、最良の選択肢は Hashed です。秘密を保管する最善の方法は、そもそも保管しないことだからです。ただし、ハッシュから元のパスワードを突き止める方法はないので、ユーザーが自分のパスワードを忘れてしまった場合、そのパスワードを回復することはできません。
悪い:
<configuration>
<system.web>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
passwordFormat="Clear"
...
/>
より良い:
<configuration>
<system.web>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
passwordFormat="Encrypted"
...
/>
最良:
<configuration>
<system.web>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
passwordFormat="Hashed"
...
/>
MinRequiredPasswordLength と MinRequiredNonalphanumericCharacters
メンバーシップ設定には、既定値からの変更が必要な値が 2 つあります。MinRequiredPasswordLength プロパティと MinRequiredNonalphanumericCharacters プロパティです。AspNetSqlMembershipProvider オブジェクトでは、これらの設定は、既定では、最低限必要なパスワードの長さは 6 文字で、英数字以外の文字は含まれなくてもよいという設定になっています。セキュリティを強化するため、これらの設定ははるかに高いレベルに設定する必要があります。英数字以外の文字が 2 文字以上含まれる、最低 10 文字のパスワードを要求する必要があります。さらに良いのは、英数字以外の文字が 4 文字以上含まれる、最低 14 文字のパスワードです。
パスワードの長さと複雑さが両刃の剣であるのは事実です。より長く複雑なパスワードを設定するようユーザーに求めると、パスワードがブルート フォース攻撃によって突き止められてしまう可能性は低下しますが、その分、ユーザーがパスワードを覚えておくことができず、書き留めざるを得なくなる可能性は高まります。これは恐ろしいセキュリティ ホールとなる可能性があるように思えますが、多くのセキュリティ専門家は、そのメリットはリスクを上回ると考えています。セキュリティの権威として有名な Bruce Schneier は、一案として、ユーザーが長くて複雑なパスワードを作成し、財布にしまっておくことを勧めています (財布は人が小さな紙切れを厳重に保管することに慣れている場所であるため)。
悪い:
<configuration>
<system.web>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
...
/>
良い:
<configuration>
<system.web>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
minRequiredPasswordLength="14"
minRequiredNonalphanumericCharacters="4"
...
/>
マイクロソフト セキュリティ At Home サイト (microsoft.com/japan/protect/yourself/password/create.mspx) でも、ユーザーがパスワードを書き留めることを勧めています。また、このサイトでは、強力なパスワードを作成し保護する方法についての追加情報も紹介されています。
ValidateRequest
クロスサイト スクリプト (XSS) は今でも、最もよく見られる Web 脆弱性です。Cenzic Inc. が 7 月に発表したレポートによると、今年の上半期では、XSS 脆弱性がすべての Web 攻撃の 28% を占めていたそうです。XSS 脆弱性が深刻な結果をもたらす可能性があることを踏まえ、私は今までにたびたび、XSS を "Web のバッファー オーバーフロー" と呼んできました。開発者が、アプリケーションをこの攻撃から守るためにできることは何でもする必要があるのはきわめて当然のことです。基本的にコストがかからない防御策があると特に良いですが、ValidateRequest がまさにそれです。
悪い:
<configuration>
<system.web>
<pages validateRequest="false" />
良い:
<configuration>
<system.web>
<pages validateRequest="true" />
ValidateRequest は、ユーザーによる入力に、よくある攻撃パターンが含まれているかどうか (入力文字列に山かっこ (<) が含まれているかどうかなど) を調べることで機能します。含まれている場合、アプリケーションは例外をスローし、要求の処理を停止します。これだけでは完全な解決策にはなりませんが (この他に必ず、出力のエンコードおよび入力の検証/機密部分削除のロジック (Microsoft Web Protection Library に組み込まれているものなど) も適用する必要があります)、ValidateRequest で多くの種類の一般的な XSS 攻撃をブロックできるのは事実です。ValidateRequest は、可能な限り有効なままにしておくのがベストです。
MaxRequestLength
ユーザーが任意の大きさの HTTP 要求をアプリケーションに送信できるようにしておくのが得策であることはめったにありません。このようにしてしまうと、サービス拒否 (DoS) 攻撃 (1 人の攻撃者が帯域幅、プロセッサ サイクル、またはディスク領域をすべて使い切ってしまい、アプリケーションが対象とするその他の正当なユーザーはアプリケーションを使用できなくなってしまうというもの) を受けやすくなります。
MaxRequestLength プロパティを適切な小さい値に設定すると、これを防ぐのに役立ちます。既定値は 4096 KB (4 MB) です。通常の要求サイズと異常な要求サイズに関する要件はアプリケーションによって異なるので、MaxRequestLength にどのような値を設定すればよいかについて確かな経験則を作るのは困難です。したがって、"悪い" 設定と "良い" 設定の例を示すのではなく、単に、この値を高く設定すればするほど DoS 攻撃を受ける危険性が高まることを覚えておくようお勧めしておきます。
<configuration>
<system.web>
<httpRuntime maxRequestLength="4096"/>
EnableViewStateMac
EnableViewStateMac の設定については、2010 年 7 月の、ビュー ステートのセキュリティに関する "セキュリティに関するブリーフィング" コラム (msdn.microsoft.com/magazine/ff797918) に書きました。このコラムを読んでいない方のために説明すると、EnableViewStateMac は、攻撃者がクライアント側のビュー ステートを改ざんするのを防ぐための防御策です。EnableViewStateMac が有効になっている場合、ASP.NET アプリケーションでは、__VIEWSTATE という隠しフォームの値に暗号化 MAC (メッセージ認証コード) を追加します。攻撃者は、(たとえば、攻撃対象者のビュー ステートを改ざんして悪意のある JavaScript を挿入するために) 無原則の攻撃用に有効な MAC を特定することはできません。したがって、攻撃者がこの方法でビュー ステートを改ざんしようとした場合、使用される MAC は無効となり、ASP.NET アプリケーションは要求をブロックします。
悪い:
<configuration>
<system.web>
<pages enableViewStateMac="false"/>
良い:
<configuration>
<system.web>
<pages enableViewStateMac="true"/>
アプリケーションをサーバー ファーム環境に展開する場合、アプリケーションでランダム キーを自動生成するのではなく、MAC のキーを手動で指定することを忘れないことも重要です (キーを手動で指定しない場合、ファーム内の各コンピューターが別々のキーを自動生成し、どのコンピューターが作成したビュー ステートの MAC も無効と見なされ、他のどのコンピューターからもブロックされます)。
キーを手動で作成する際に、ビュー ステートのセキュリティを最大限に高めるために従う必要のある追加のガイドラインがいくつかあります。まず、SDL によって承認された暗号アルゴリズムの 1 つを指定するようにしてください。Microsoft .NET Framework 3.5 またはそれ以前のバージョンを使用するアプリケーションにとって、これは、SHA1 (これが既定のアルゴリズムです) または AES の使用を意味します。.NET Framework 4 を使用するアプリケーションの場合は、HMACSHA256、HMACSHA384、または HMACSHA512 を使用することもできます。MD5 などの脆弱なアルゴリズムは避けてください。
悪い:
<configuration>
<system.web>
<machineKey validation="MD5" validationKey="..."/>
良い:
<configuration>
<system.web>
<machineKey validation="AES" validationKey="..."/>
強力なキーを選択するのは、強力なアルゴリズムを選択するのと同じくらい重要です。暗号的に強力な乱数ジェネレーターを使用して、64 バイトのキー (HMACSHA384 または HMACSHA512 をキー アルゴリズムとして使用している場合は 128 バイト) を生成します。2010 年 7 月の "セキュリティに関するブリーフィング" コラム (前述) では、適切なキーを生成するための参考用サンプル コードを提供しています。
悪い:
<configuration>
<system.web>
<machineKey validation="AES" validationKey="12345"/>
良い:
<configuration>
<system.web>
<machineKey validation="AES" validationKey="143a907bb73069a2fe7c..."/>
ViewStateEncryptionMode
攻撃者によるビュー ステートの改ざんを防ぐためにアプリケーションのビュー ステートに MAC を適用する必要があるのと同様に、攻撃者に読み取られることを防ぐためにビュー ステートを暗号化することも必要です。どのビュー ステートにも機密情報がまったく存在しないと 100% 確信できる場合以外は、ビュー ステートの暗号化と保護のために ViewStateEncryptionMode プロパティを設定しておくのが安全です。
悪い:
<configuration>
<system.web>
<pages viewStateEncryptionMode="Never"/>
良い:
<configuration>
<system.web>
<pages viewStateEncryptionMode="Auto"/>
ここでも、EnableViewStateMac の場合と同様に、アプリケーションがビュー ステートの暗号化に使用する暗号アルゴリズムをいくつかの選択肢から選ぶことができます。ただし、SDL 暗号化標準で現在承認されている唯一のアルゴリズムである AES を常に選択するのがベストです。
悪い:
<configuration>
<system.web>
<machineKey decryption="DES" decryptionKey=""/>
良い:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey=""/>
最後に、アプリケーションをサーバー ファームに展開する場合はキーを手動で指定する必要があることを忘れないでください。キーの値は必ず、24 バイトの暗号的にランダムな値に設定します。
悪い:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="12345"/>
良い:
<configuration>
<system.web>
<machineKey decryption="AES" decryptionKey="143a907bb73069a2fe7c..."/>
UseUnsafeHeaderParsing
開発者は、難しいバグにすっかりいら立ってしまうと、アプリケーションへの影響をきちんと理解せずに、問題の解決方法として目にした変更を何でも実装してしまうことがよくあります。UseUnsafeHeaderParsing の設定はその良い例です。ほとんどの人は、プロパティ名に含まれる "unsafe" という単語を見ただけでも警戒するでしょうが、インターネットを簡単に検索してみると、このプロパティを有効にすることを開発者に勧めている検索結果が文字どおり何千件も見つかります。UseUnsafeHeaderParsing を有効にすると、アプリケーションは HTTP RFC 仕様の多くを無視し、形式が正しくない要求を解析しようとします。このプロパティを有効にすると、アプリケーションは HTTP 標準に違反する HTTP クライアントと連携できるようになる可能性がありますが (これが、多くの人がこの方法を問題の解決方法として勧めている理由なのですが)、これにより、アプリケーションが、形式が正しくないヘッダーによる攻撃を受けやすくなる可能性もあります。安全を第一に優先し、この設定は無効なままにしておいてください。
悪い:
<configuration>
<system.net>
<settings>
<httpWebRequest
useUnsafeHeaderParsing=
"true"/>
良い:
<configuration>
<system.net>
<settings>
<httpWebRequest
useUnsafeHeaderParsing=
"false"/>
Web Application Configuration Analyzer (WACA)
いくつかの危険な構成設定を見てきたので、今度は、コード内のこうした設定の検出を自動化するのに役立つツールについて見ていきましょう。結局のところ、手動のコード レビューが役に立つこともありますが、自動化された分析の方がより綿密で一貫性があります。また、自動化された分析を使用すると、XML ファイルの手動レビューという退屈で骨の折れる作業を行わなくて済むようになり、より興味深い問題の解決に費やすことができる時間が増えます。
マイクロソフト情報セキュリティツール チームは、いくつかの優れたセキュリティ ツールをリリースしています。これには、Microsoft SDL の一環として、マイクロソフト社内の Microsoft .NET Framework 製品/サービスすべてで使用が義務付けられている 2 つのツール (AntiXSS/Web Protection Library および CAT.NET) が含まれます。最新のリリースである WACA は、危険性を秘めた構成ミス (この記事で説明したものや、最もよく見られる web.config の脆弱性トップ 10 に関する以前の記事で説明したものなど) を検出するようにデザインされています。WACA によるチェックの例を以下に示します。
- トレースは有効になっているか。
- MaxRequestLength は大きすぎるか。
- HttpOnly Cookie は無効になっているか。
- フォーム認証ログインに SSL が必須となっているか。
- EnableViewStateMac 属性は false に設定されているか。
また、WACA では、IIS 自体の構成ミス、SQL データベースの構成ミス、さらにはシステム レベルの問題もチェックすることができます。たとえば、次のようなチェックを行うことができます。
- Windows ファイアウォール サービスは無効になっているか。
- ローカル管理者の名前は "Administrator" か。
- IIS ログ ファイルはシステム ドライブ上にあるか。
- アプリケーションの仮想ディレクトリで実行は有効になっているか。
- SQL サーバー上にサンプル データベースは存在するか。
- SQL サーバーで xp_cmdshell は有効になっているか。
開発者とテスターは、おそらく、主にアプリケーションの構成設定をチェックするために WACA を使用するでしょうが、システム管理者とデータベース管理者にとっては、IIS、SQL、およびシステムの設定をチェックするという使い方が役立つでしょう (図 1 参照)。WACA には、SDL の要件と patterns & practices のコーディング ガイドラインに基づく、全部で 140 を超える数のチェックが用意されています。
図 1 Web Application Configuration Analyzer のルール
WACA のもう 1 つの非常に役立つ機能は、WACA のスキャン結果を基にして、Team Foundation Server (TFS) のチーム プロジェクトで作業項目やバグを自動的に作成できるというものです。これは、SDL プロセス テンプレートまたは MSF-Agile+SDL プロセス テンプレートから作成されたチーム プロジェクトと共に使用すると、特に役立ちます。WACA の TFS セットアップ ページで、"Origin" (ソース) というテンプレート フィールドを "Web Application Configuration Analyzer" という値にマップします。バグ レポートと傾向グラフを確認する際は、WACA の結果をフィルターし、ドリルダウンして、潜在的な脆弱性の検出に非常に効果的であることを実感することができます (図 2 参照)。
図 2 WACA と Team Foundation Server の統合
WACA の詳細については、Microsoft IT InfoSec グループのページ (msdn.microsoft.com/security/dd547422、英語) を参照したり、WACA プロジェクトのプログラム マネージャーである Anil Revuru によるツールのデモ ビデオ (msdn.microsoft.com/security/ee909463、英語) を見たりして確認することもできますが、最も良い方法は、ツールをダウンロードして自分で試してみることです (tinyurl.com/3x7bgfd、(英語))。
常に設定をチェックする
安全な開発のためのガイドラインとベスト プラクティスのすべてに従ってアプリケーションを開発しても、web.config 構成ファイルでの単純なミスのせいでハッキングされてしまう可能性があるというのは、いら立たしいことです。web.config ファイルはいつでも変更されるようにデザインされていて、構成のミスはアプリケーションのコーディングを終えてアプリケーションを運用環境に移してから何年もたったときに見つかる可能性があることに気付くと、さらにいら立たしく感じます。構成設定を常にチェックすることは重要です。チェックには手動の検査だけでなく自動化されたツールも使用し、また、開発ライフサイクル中だけではなく運用時にもチェックを行うようにします。
正規表現による DoS 攻撃についての補足
話はまったく変わりますが、2010 年 5 月の "セキュリティに関するブリーフィング" コラム (msdn.microsoft.com/magazine/ff646973) で、私は、2009 年 9 月にイスラエルで開催された OWASP カンファレンスで Checkmarx が説明した、RegEx による DoS 攻撃について書きました。そのコラムでは、Visual Studio データベース プロジェクトのデータ生成計画機能をベースにした、RegEx による DoS 攻撃に備えるためのファザー用コードも提供しました。このアプローチは技術的には適切であり、RegEx の脆弱性を検出するのに役立ちましたが、テスト データを生成するのが少し面倒だったことは認めざるを得ません。また、このアプローチを使用するには Visual Studio データベース プロジェクトのライセンスを所有している必要がありました。そのため、私は、データ生成に関する詳細処理を自動的に行う、RegEx の脆弱性を検出するためのファジー テストを行う新しいツール (無償でダウンロード可能) をSDL チームがリリースしたことをご報告できるのをうれしく思っています。このツールには、(.NET Framework 3.5 以外には) 外部依存関係はありません。このツールを図 3 に示します。
図 3 SDL Regex Fuzzer
SDL Regex Fuzzer は microsoft.com/sdl (英語) からダウンロードできます。ぜひお試しになって、ご意見をお聞かせください。
Bryan Sullivan は、マイクロソフトのセキュリティ開発ライフサイクル チームのセキュリティ プログラム マネージャーであり、Web アプリケーションと Microsoft .NET Framework のセキュリティ問題を専門に扱っています。『Ajax セキュリティ』(毎日コミュニケーションズ、2008 年) の著者でもあります。
この記事のレビューに協力してくれた技術スタッフの Anil Revuru に心より感謝いたします。