IIS 7 での ASP.NET 2.0 の互換性に影響する変更点

公開日: 2008 年 3 月 15 日 (作業者: chriskno (英語))

更新日: 2009 年 9 月 9 日 (作業者: chriskno (英語))

はじめに

IIS 7 の ASP.NET 2.0 アプリケーションは、既定で ASP.NET 統合モードを使用してホストされます。この新しいモードによって、Web サイト全体のフォーム認証などの有用な ASP.NET 機能を使用したり、URL 書き換え、承認、ログなどを IIS レベルで処理する ASP.NET モジュールを開発することができ、ほぼ無限のエキサイティングなシナリオが可能になります。IIS 7 における ASP.NET 統合の詳細については、「ASP.NET と IIS 7 の統合」を参照してください。

マイクロソフトでは、IIS 7 で ASP.NET アプリケーションをより強力にする一方で、既存の ASP.NET アプリケーションをこの新しいプラットフォームに移行しても確実に動作することを目的として真剣に取り組んできました。これは ASP.NET のコア エンジン全体のアーキテクチャを再構築するという大きな変更でしたが、この目的を満たす大きな成功を収めました。その結果、ASP.NET アプリケーションのほとんどは手を加えなくても動作します。

この記事には、Windows Vista SP1 および Windows Server 2008 の IIS 7 に ASP.NET アプリケーションを展開するときに遭遇する可能性のある、動作上の変更点を記載しています。特段の記載がない限り、これらの互換性に影響する変更点は、既定の ASP.NET 統合モードを使用したときにのみ問題となります。

クラシック ASP.NET モードの使用

IIS 7 には、レガシ クラシック ASP.NET 統合モードを使用して ASP.NET アプリケーションを実行する機能もあります。このモードは、IIS の過去のバージョンでの ASP.NET と同じように動作します。ただし、可能な場合は、統合モードで動作するようにアプリケーションに変更を加えるという回避策を強く推奨します。アプリケーションをクラシックモードに移すと、統合モードで可能になる ASP.NET の向上点を活用できなくなります。また、将来マイクロソフトおよびサード パーティが統合モードを必要とする機能を提供したときに、それらを活用できません。クラシック モードは、指定されている回避策を適用できない場合の最後の手段としてください。クラシック モードへの移行の詳細については、ASP.NET 統合モードの変更方法についてのセクションを参照してください。

以下に、互換性に影響する変更点を詳細に示します。その他の詳細と回避策の情報が含まれるブログ投稿がある場合はリンクを掲載しています。特定の問題について詳細な情報が必要な場合は、IIS.net フォーラム(英語)に質問を投稿してください。

互換性に影響する変更点

移行エラー

これらのエラーは、統合モードで ASP.NET 構成が適用される方法の変更が原因で発生します。IIS は、この構成を自動的に検出し、アプリケーションの移行を求めるエラーを発行するか、移行が許容されない場合 (後述の互換性に影響する変更点の 3 番を参照してください) にクラシック モードに移行します。

1. <httpModules> または <httpHandlers> で構成を指定している場合、ASP.NET アプリケーションの移行が必要となる

"500 - 内部サーバー エラーです" が発生します。これには、"HTTP エラー 500.22"、および "HTTP エラー 500.23: **ASP.NET 設定が、統合されたマネージ パイプライン モードで適用されないことが検出されました" が含まれます。統合モードでは、ASP.NET モジュールおよびハンドラーが IIS の <handlers> および <modules> 構成セクションに指定されている必要があるので、このエラーが発生します。

回避策

A. 統合モードで正しく動作させるには、アプリケーション構成の移行が必要です。次のように AppCmd を使用してアプリケーション構成を移行できます。

> %windir%\system32\inetsrv\Appcmd migrate config "<アプリケーション パス>"

B. <system.web>/<httpModules> および <system.web>/<httpHandlers> 構成に含まれるカスタム エントリを <system.webServer>/<handlers> および <system.webServer>/<modules> 構成セクションに手動で移行します。次に、<httpHandlers> および <httpModules> 構成を削除するか、またはアプリケーションの web.config に次のコードを追加します。

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>
2. ASP.NET アプリケーションの構成に <identity impersonate='true'> を指定して要求偽装を有効にすると警告が発生する

"500 - 内部サーバー エラーです" が発生します。これは、"HTTP Error 500.24: **ASP.NET 設定が、統合されたマネージ パイプライン モードで適用されないことが検出されました" に該当します。ASP.NET 統合モードでは、BeginRequest および AuthenticateRequest パイプライン段階で要求 ID を偽装できないので、このエラーが発生します。

回避策

A. アプリケーションが BeginRequest および AuthenticateRequest 段階 (統合モードではこれらの段階でのみ偽装が不可能です) での要求ユーザーの偽装に依存していない場合は、アプリケーションの web.config に次のコードを追加し、このエラーを無視してください。

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer> 

B. アプリケーションが BeginRequest および AuthenticateRequest での偽装に依存している場合、または依存しているかどうか不明な場合は、クラシック モードに移行してください。

3. アプリケーション構成に暗号化された <identity> セクションが含まれていると構成エラーが発生する

"500 - 内部サーバー エラーです" が発生します。これは、"HTTP エラー 500.19: **ページに関連する構成データが無効であるため、要求されたページにアクセスできません" に該当します。詳細なエラー情報として、「**構成セクションの暗号化はサポートされていません」と表示されます。IIS が <identity> セクションを検証しようとして、セクション レベルの暗号化の読み取りに失敗するので、このエラーが発生します。

回避策

A. アプリケーションに、互換性に影響する変更点 2 番の要求の偽装についての問題がない場合は、互換性に影響する変更点 1 番で説明したように AppCmd を使用してアプリケーション構成を移行してください。

> %windir%\system32\inetsrv\Appcmd migrate config "<ApplicationPath>" 

こうすることで、残りのアプリケーション構成が確実に移行され、アプリケーションの web.config に次のコードが自動的に追加されて <identity> セクションが無視されます。

<identity> section:

<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
</system.webServer>

B. アプリケーションに、要求偽装についての問題がある場合は、クラシック モードに移行してください。

認証、承認、および偽装

統合モードでは、IIS および ASP.NET 両方の認証段階が統合されました。そのため、IIS 認証の結果は、ASP.NET と IIS 認証メソッドの両方が完了する PostAuthenticateRequest 段階まで利用できません。この影響は、以下のとおりです。

4. アプリケーションで FormsAuthentication と WindowsAuthentication を同時に使用できない

クラシック モードとは異なり、ASP.NET で フォーム認証を使用しながら、Windows 認証、基本認証などの IIS 認証メソッドでユーザーに認証を要求することはできません。フォーム認証が有効な場合、匿名認証以外のすべての IIS 認証メソッドが無効化されます。
さらに、フォーム認証を使用するときに、以下の変更点が影響します。

- LOGON_USER サーバー変数に、フォーム認証ユーザーの名前が設定されます。

- 認証されたクライアントを偽装することはできません。認証されたクライアントを偽装するには、フォーム認証ではなく Windows ユーザーを作成する認証メソッドを使用する必要があります。

回避策

A. IIS 7 でフォーム認証および別の IIS 認証メソッドを使用する 2 段階の認証スキーマの実装(英語) についての記事で説明されているパターンを使用するようにアプリケーションを変更してください。

5. 既定では Windows 認証はカーネルで実行され、最初のリクエストで資格情報を送信する HTTP クライアントが失敗することがある

IIS 7 では、既定で IIS 7 カーネル モード認証が有効になっています。これによって、Windows 認証のパフォーマンスが向上し、Kerberos 認証プロトコルの展開が単純化されています。しかし、カーネル モード認証の設計上の制限が原因で、最初の要求で Windows 資格情報を送信するクライアントが失敗することがあります。通常のブラウザー クライアントは、常に最初の要求を匿名で送信するので、この影響を受けません。

メモ : この互換性に影響する変更点は、クラシックと統合の両モードに適用されます。

回避策

A. system.webServer/security/authentication/windowsAuthentication セクションで userKernelMode を false に設定し、カーネル モード認証を無効にしてください。次の AppCmd でも同じことができます。

> %windir%\system32\inetsrv\appcmd set config /section:windowsAuthentication /useKernelMode:false
6. Passport 認証がサポートされない

"ASP.NET 500 - サーバー エラー: PassportManager オブジェクトを初期化できませんでした。**Microsoft Passport がサーバーに適切にインストールされていることを確認してください" というエラーが発生します。Windows Vista および Windows Server 2008 では Passport 認証がサポートされなくなりました。メモ: この互換性に影響する変更点は、クラシックと統合の両モードに適用されます。

7. PostAuthenticateRequest より前にモジュール内で HttpRequest.LogonUserIdentity がアクセスされると InvalidOperationException がスローされる

"ASP.NET 500 – サーバー エラー: **このメソッドは、認証イベントの後に限り呼び出すことができます" というエラーが発生します。PostAuthenticateRequest より前に HttpRequest.LogonUserIdentity がアクセスされると InvalidOperationException がスローされます。これは、クライアントが認証されるまでこのプロパティの値が未知であることが原因です。

回避策

A. PostAuthenticateRequest の前に HttpRequest.LogonUserIdentity にアクセスしないようにコードを変更してください。

8. BeginRequest および AuthenticateRequest 段階でモジュールにクライアント偽装が適用されない

PostAuthenticateRequest 段階までは、認証されたユーザーは未知です。したがって、BeginRequest および AuthenticateRequest 段階で実行される ASP.NET モジュールに対しては、ASP.NET は認証されたユーザーを偽装しません。これらの段階でのアクセスの許可やリソースへのアクセスのためにクライアントの偽装に依存するカスタム モジュールが存在する場合に、アプリケーションに影響することがあります。

回避策

A. BeginRequest および AuthenticateRequest 段階でクライアント偽装を必要としないようにアプリケーションを変更してください。

9. global.asax に DefaultAuthentication_OnAuthenticate メソッドを定義すると PlatformNotSupportedException がスローされる

"ASP.NET 500 – サーバー エラー: **DefaultAuthentication.Authenticate メソッドは、IIS 統合パイプライン モードではサポートされていません" というエラーが発生します。統合モードでは、DefaultAuthenticationModule.Authenticate イベントが実装されていないので、このイベントは発行されません。クラシック モードでは、認証が行われなかった場合に、このイベントが発行されます。

回避策

A. DefaultAuthentication_OnAuthenticate イベントに依存しないようにアプリケーションを変更し、代わりに、認証されたユーザーの存在を判断するために、HttpContext.User が **null かどうかを検査する IHttpModule を記述してください。

10. 要求が匿名だった場合に、global.asax に WindowsAuthentication_OnAuthenticate を実装しているアプリケーションには通知されない

global.asax に WindowsAuthentication_OnAuthenticate メソッドを定義すると、匿名要求に対してこのメソッドは呼び出されません。これは、WindowsAuthentication モジュールが OnAuthenticate イベントを発行できるようになった後で匿名認証が行われることが原因です。

回避策

A. WindowsAuthentication_OnAuthenticate イベントを使用しないようにアプリケーションを変更し、代わりに、PostAuthenticateRequest 内で実行され HttpContext.User を検査する IHttpModule を実装します。

要求制限と URL 処理

以下は、受信する要求およびその URL を IIS が処理する方法による新しい制限の結果生じた変更点です。

11. 要求 URL のパス (クエリ文字列には該当しません) にエンコードされていない "+" 文字が含まれていると、既定で拒否される

"HTTP エラー 404.11 – 未検出: **要求フィルタ モジュールが、ダブル エスケープ シーケンスを含む要求を拒否するように構成されています" というエラーが発生します。IIS は既定で、URL の二重エンコードの試行を拒否するように構成されています。この試行は、通常、正規化攻撃の兆候です。

回避策

A. URL パス内に "+" 文字を必要とするアプリケーションを使用する場合は、アプリケーションの web.config 内の **system.webServer/security/requestFiltering 構成セクションに **allowDoubleEscaping 属性を設定して、この検証を無効にできます。ただし、こうすることで、アプリケーションが悪質な URL に対して脆弱になる可能性があります。

<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
12. 2,048 バイトを超えるクエリ文字列を持つ要求は、既定で拒否される

"HTTP エラー 404.15 – 未検出: **要求フィルタ モジュールが、クエリ文字列が長すぎる要求を拒否するように構成されています" というエラーが発生します。IIS は既定で、2,048 バイトを超えるクエリ文字列を拒否するように構成されています。これは、長いクエリ文字列を使用するアプリケーションや、累積でクエリ文字列サイズの構成制限を超えるフォーム認証などの Cookie なしの ASP.NET 機能を使用するアプリケーションに影響する可能性があります。

メモ : この互換性に影響する変更点は、クラシックと統合の両モードに適用されます。

回避策

A. アプリケーションの web.config の **system.webServer/security/requestFiltering 構成セクション内で、**requestLimits 要素に **maxQueryString 属性を設定して、最大クエリ文字列サイズを増やすことができます。

<system.webServer>
<security>
<requestFiltering>
<requestLimits maxQueryString="新しい値をバイト単位で指定" />
</requestFiltering>
</security>
</system.webServer>

応答ヘッダー処理の変更点

これらの変更点は、アプリケーションが応答ヘッダーを生成する方法に影響します。

13. IIS は (ASP.NET の enableHeaderChecking が false に設定されていても) 常に、応答ヘッダー内の新しい行を拒否する

アプリケーションが改行 (\r や \n の任意の組み合わせ) を含むヘッダーを生成すると、"ASP.NET 500 - サーバー エラー: **値が期待される範囲内にありません" というエラーが発生します。IIS は、改行を含む応答ヘッダーを生成する試みを (ASP.NET の enableHeaderChecking が無効にされていても) 常に拒否します。これは、ヘッダー分割攻撃を防ぐための動作です。

メモ : この互換性に影響する変更点は、クラシックと統合の両モードに適用されます。

14. 応答が空のときに Content-Type ヘッダーが抑制されない

アプリケーション設定した Content-Type ヘッダーは、応答が消去された場合であっても存在し続けます。ASP.NET コンテンツ タイプへの要求は、通常、アプリケーションで上書きされない限り、応答内に "Content-Type: text/html" として存在します。

回避策

A. 通常、これは互換性に影響しませんが、応答を消去するときに **HttpResponse.ContentType プロパティを明示的に **null に設定することで、Content-Type ヘッダーを削除できます。

15. HttpResponse.ClearHeaders で応答ヘッダーを消去すると、既定の ASP.NET ヘッダーが生成されず、クライアントでの応答のキャッシュを防ぐ Cache-Control: private ヘッダーがなくなることがある

HttpResponse.ClearHeaders を使用すると、"Content-Type: text/html"、"Cache-Control: private" などの既定の ASP.NET 応答ヘッダーが再生成されません (クラシック モードでは再生成されます)。この動作は、ASP.NET モジュールが任意のリソース タイプの要求のためにこの API を呼び出すことがあり、ASP.NET 特有のヘッダーの生成は適切ではないからです。"Cache-Control" ヘッダーがないと、ダウンストリーム ネットワークのデバイスのいくつかで応答がキャッシュされることがあります。

回避策

A. ダウンストリーム ネットワークのデバイスでのキャッシュを防ぐ必要がある場合、応答を消去するときに "Cache-Control: private" ヘッダーを能動的に生成するようにアプリケーションを変更してください。

アプリケーションおよびモジュール イベントの処理の変更点

これらの変更点は、アプリケーションおよびモジュール イベントの処理が行われる方法に影響します。

16. global.asax 内の Application_Start の HttpContext.Current プロパティを通じて要求にアクセスできない

アプリケーションが、初期化の一環として global.asax 内の Application_Start メソッドの現在の要求コンテキストにアクセスすると、"ASP.NET 500 – サーバー エラー: **このコンテキストでは要求が有効ではありません" というエラーが発生します。ASP.NET アプリケーションの初期化が、それをトリガする要求から切り離されたので、このエラーが発生します。クラシック モードでは、HttpContext.Current にアクセスして、要求コンテキストに間接的にアクセスすることが可能でした。統合モードでは、このコンテキストは実際の要求を表すものではなくなったので、Request および Response オブジェクトにアクセスしようとすると例外が生成されます。

回避策

この問題の詳細および回避策については、**Application_Start での "このコンテキストでは要求が有効ではありません" 例外(英語)**についての記事を参照してください。

17. モジュールのイベント ハンドラーの実行順がクラシック モードとは異なる

以下の点が異なります。

- 各イベントに対し、各モジュールのイベント ハンドラーは、<modules> 構成セクションに構成されているモジュール順に実行されます。global.asax のイベント ハンドラーは最後に実行されます。

- PreSendRequestHeaders および PreSendRequestContent イベントに登録しているモジュールには、<modules> 構成セクションでの順番とは逆に通知されます。

- 各イベントに対して、各モジュールの同期イベント ハンドラーは、非同期ハンドラーの前に実行されます。これ以外の場合は、イベント ハンドラーは登録された順に実行されます。

これらのイベントのいずれかで実行される複数のモジュールが構成されているアプリケーションは、イベント順の依存関係を共有している場合に、これらの変更点の影響を受けることがあります。これは、ほとんどのアプリケーションに該当しないと考えられます。モジュールの実行順は、失敗した要求トレース ログで確認できます。

回避策

A. 実行順で問題が発生するモジュールの順番を、**system.webServer/modules 構成セクションで変更してください。

18. 初期の要求処理段階で、ASP.NET モジュールは、ASP.NET に渡される前に IIS によって拒否される可能性がある要求を確認する (BeginRequest 段階で実行されるモジュールが認証を必要とするリソースへの匿名要求を確認する場合など)

ネイティブ IIS モジュールが利用できるパイプライン段階であればどこでも、ASP.NET モジュールを実行できます。そのため、ASP.NET に渡される前に認証段階で拒否される可能性のある要求 (認証を必要とするリソースに対する匿名要求など) や、その他の段階で拒否される可能性のある要求が、ASP.NET モジュールを実行する可能性があります。これは、すべての要求処理段階に IIS を拡張する ASP.NET モジュールを有効化するための仕様です。

回避策

A. 要求の処理において、後で拒否される可能性のある要求を確認するという、アプリケーション固有の問題を回避するためにコードを変更してください。要求の処理において、後で発行されるパイプライン イベントに登録するモジュールの変更が必要になることもあります。

その他のアプリケーションの変更点

ASP.NET アプリケーションおよび API の動作におけるその他の変更点は以下のとおりです。

19. DefaultHttpHandler がサポートされないので、DefaultHttpHandler のサブクラスに依存しているアプリケーションは要求を処理できない

アプリケーションで DefaultHttpHandler または DefaultHttpHandler から派生したハンドラーが使用されている場合、アプリケーションは正しく機能しません。統合モードでは、DefaultHttpHandler から派生したハンドラーは、要求の処理のために IIS に要求を戻すことができず、代わりに要求されたリソースを静的なファイルとして処理します。統合モードでは、DefaultHttpHandler を使用することなく、すべての要求に対して ASP.NET モジュールを実行できます。

回避策

A. ワイルドカードを使用して ASP.NET をすべての要求に割り当ててから DefaultHttpHandler の派生ハンドラーを使用して IIS に要求を戻す代わりに、アプリケーションを変更して、モジュールを使用してすべての要求を処理するようにしてください。

20. 例外が発生した後で応答に書き込むことができる

統合モードでは、例外が発生した後で、(通常は LogRequest および EndRequest イベントに登録しているモジュール内で) 追加の応答を書き込んで表示できます。クラシック モードではできません。要求の最中にエラーが発生し、例外が発生した後でアプリケーションが EndRequest で応答に書き込むと、EndRequest で書き込まれた応答情報が表示されます。これは、未処理の例外が含まれている要求にのみ影響します。例外の後の応答への書き込みを回避するには、アプリケーションが応答に書き込む前に HttpContext.Error または HttpResponse.StatusCode を確認する必要があります。

21. 例外が前のパイプライン段階で発生した場合に、ClearError API を使用して応答に例外が書き込まれることを回避できない
回避策

A. 例外がスローされたときに常に発行される Application_OnError イベント ハンドラーから Server.ClearError を呼び出すようにアプリケーションを変更してください。

22. HttpResponse.AppendToLog が URL の先頭に自動的にクエリ文字列を追加しない

要求ログ ファイルに記録される URL にカスタム文字列を追加するために HttpResponse.AppendToLog を使用する場合は、この API に渡す文字列の先頭にクエリ文字列を能動的に追加する必要があります。そのため、既存のコードでこの API が使用されると、記録された URL からクエリ文字列が失われることがあります。

回避策

A. HttpResponse.AppendToLog に渡す文字列の先頭に能動的に HttpResponse.QueryString.ToString() を追加するように、アプリケーションを変更してください。

その他の変更点

その他の変更点は以下のとおりです。

23. 統合モードでは、ASP.NET スレッド設定を使用して要求の同時実行性を制御できない

** system.web/httpRuntime 構成セクションの **minFreeThreads と **minLocalRequestFreeThreads 設定、および **processModel 構成セクションの **maxWorkerThreads 設定は、ASP.NET で使用されるスレッド メカニズムを制御しなくなりました。その代わり、ASP.NET は IIS スレッド プールに依存し、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0 キー内の **MaxConcurrentRequestsPerCPU の DWORD 値 (既定値は 12) を設定することで、同時実行要求の最大数を制御できるようになりました。この設定はグローバルなので、アプリケーション プールやアプリケーションごとに変更することはできません。

回避策

A. アプリケーションの同時実行性を制御するには、MaxConcurrentRequestsPerCPU 設定を使用してください。

24. 統合モードでは ASP.NET アプリケーション キューが使用されないので、"ASP.NET Applications\Requests in Application Queue" パフォーマンス カウンターの値が常に 0 になる

統合モードでは、ASP.NET はアプリケーション キューを使用しません。

25. アプリケーションのルート web.config ファイルが変更されると、IIS 7 は常に ASP.NET アプリケーションを再起動するので、waitChangeNotification および maxWaitChangeNotification 属性の効果がない

IIS 7 は web.config ファイルも監視し、system.web/httpRuntime 構成セクションの **waitChangeNotification および **maxWaitChangeNotification 属性などの ASP.NET 変更通知設定に関係なく、そのファイルに対応する ASP.NET アプリケーションを再起動します。

IIS 7 の統合モードに速やかに移行し、IIS 7 の機能および統合された強力な ASP.NET を、アプリケーションですぐにご活用ください。

これらの互換性に影響する変更点について問題が生じたり、ここに記載されている以外の動作の変化がアプリケーションに生じた場合は、IIS.net フォーラム (英語) に投稿してください。