カスタム IIS 7.0 サーバーを構築する
作成者: Mike Volodarsky
はじめに
IIS 6.0 以前のバージョンでは、サーバー自体の内部で広く使用されているサーバー機能のほとんどが実装されています。 これに対し、IIS 7.0 以降の Web サーバー エンジンでは、事実上すべてのサーバー機能がプラグ可能なコンポーネントとして提供されるモジュール アーキテクチャが提供されます。 これにより、全体にわたって次のような大幅な改善が可能になります。
- サーバーに読み込まれる/サーバーで使用される機能のセットを正確に制御し、不要な機能を削除してサーバーの攻撃対象領域/メモリ占有領域を減らす機能
- 各機能をサード パーティまたはカスタム実装に置き換える機能
- サーバー トポロジでの役割に基づいてサーバーを特殊化する機能
- 細かい粒度とアプリケーションの委任可能なレベルの両方で、サーバーの機能セットを高度に制御する
モジュールと呼ばれるこれらのサーバー コンポーネントは、アプリケーション プール ワーカー プロセスの初期化中に読み込まれ、サーバーで要求処理サービスを提供します。 各 IIS 7.0 以降のアプリケーションは、アプリケーションに対して有効になっているモジュールによって提供されるサービスと、これらのサービスで使用される関連コンテンツの組み合わせです。 サーバーでは、モジュールによって果たされる 2 つの主な役割が提供されます。
- 認証や出力キャッシュなどの要求サービスの提供 (IIS 6.0 の ISAPI フィルターと同様)
- 静的ファイル処理、CGI、ASP.NET ページ処理などの要求処理の提供 (IIS 6.0 の ISAPI 拡張機能と同様)
さまざまなモジュールを有効にすることで、サーバー上のアプリケーションに必要なサービスを提供するようにサーバーを構成できます。
この記事で説明するタスクは次のとおりです。
- サーバー構成、既定、および既定でサーバーに読み込まれたモジュールのセットを確認する
- すべてのモジュールを削除してサーバーを最小限の構成になるまで取り除き、フットプリントへの影響を調べる
- 特定のシナリオをサポートするモジュールを段階的に追加して、カスタム サーバーを構築する
既定のモジュール構成の確認
メイン サーバー構成は、IIS 構成ディレクトリ %windir%\system32\inetsrv\config\
にある applicationHost.config ファイルに含まれています。 <system.webServer>
セクション グループに含まれる次の構成を確認します。
<globalModules>
セクション。 このサーバー レベルのセクションには、サーバー ワーカー プロセスによって読み込まれたモジュールの一覧と、その機能を実装する関連するネイティブ DLL が含まれています。
<modules>
セクション。 このアプリケーション レベルのセクションには、特定のアプリケーションで有効になっているモジュールの一覧が含まれています。 このセクションは、アプリケーションでアクティブにする必要がある読み込まれたモジュールのサブセットを選択し、追加のアプリケーション レベルのモジュールを読み込むのにも役立ちます。
<handlers>
セクション。 この URL レベルのセクションには、処理を行う特定のモジュールに受信要求をマップするためにサーバーで使用されるハンドラー マッピングが含まれています。 これは IIS 6.0 スクリプトマップまたは ASP.NET に似ていて、ネイティブおよびマネージド コンテンツ タイプ ハンドラーの両方への要求の統合マッピングが提供されます。
すべての IIS モジュールの詳細については、IIS 7.0 以降のモジュールの概要に関するページを参照してください。
構成バックアップを作成する
まず、必要に応じて復元できるようにサーバー構成をバックアップします。 管理者として実行されているコマンド プロンプトから次のコマンドを実行します。
%windir%\system32\inetsrv\appcmd add backup initial
その後、以下を実行してサーバー構成を初期状態に復元できます。
%windir%\system32\inetsrv\appcmd restore backup initial
モジュールの既定の一覧を確認する
<system.webServer>/<globalModules> セクションに移動します。 サーバー レベルでのみ構成できるこのセクションには、各サーバー ワーカー プロセスによって読み込まれるモジュールが含まれています。 各エントリでは、特定の名前と、そのモジュールの機能を実装する DLL を使用してモジュールが構成されます。
<globalModules>
<!--several modules omitted -->
<add name="BasicAuthenticationModule" image="…\authbas.dll" />
<add name="WindowsAuthenticationModule" image="…\authsspi.dll" />
</globalModules>
既定のサーバー構成のさまざまなモジュールの名前を調べます。IIS 6.0 のサーバーの一部として提供される使い慣れたサービスが表示されます。
Windows 認証モジュール、NTLM 要求認証
<add name="WindowsAuthenticationModule" image="…\authsspi.dll" />
静的ファイル ハンドラー モジュール (静的ファイルを提供)
<add name="StaticFileModule" image="…\static.dll" />
動的圧縮モジュール、応答の圧縮
<add name="DynamicCompressionModule" image="…\compdyn.dll" />
<system.webServer>/<modules> セクションに移動します。 サーバーまたはアプリケーション レベルで構成できるこのセクションでは、<globalModules> セクションに読み込まれたモジュールのうち、特定のアプリケーションに対して有効にするモジュールを指定します。 ほとんどの場合、このセクションでは、セクションで確認したモジュールの名前が一覧表示され、すべてのアプリケーションで既定で有効になります。
Note
一覧の最後にいくつかの追加項目があります。これらは、ASP.NET 機能拡張モデルを使用して開発されたマネージド モジュールです。 マネージド モードの構築の詳細については、「.NET を使用したモジュールの開発」チュートリアルを参照してください。
<system.webServer>/<handlers> セクションに移動します。 サーバー、アプリケーション、または URL レベルで構成できるこのセクションでは、要求の処理方法を指定します。 モジュールは通常、各要求に参加しますが、ハンドラーでは特定の URL の要求のみが取得されます。
モジュールの良い例が圧縮モジュールです。 圧縮モジュールでは各応答を確認し、必要に応じて圧縮します。 ASP.NET ページ ハンドラーは、ハンドラーの良い例です。 拡張子が .aspx の要求など、それにマップされている要求のみを受け取ります。 <handlers>
一覧では、URL と動詞に基づく要求と、この要求の処理に使用される処理モジュールの間のマッピングを定義します。 また、各マッピングの構成に使用される追加情報もあります。これは、このトピックの焦点ではありません。
<handlers>
<!-- certain details omitted -->
<add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" ... />
<add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" ... />
<add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" ... />
</handlers>
サーバー フットプリントの検討
Internet Explorer を開き、次の URL を指定して Enter キーを押してサーバーに要求を行います。
http://localhost/iisstart.htm
これにより、サーバー アプリケーション プールが開始され、iisstart.htm ドキュメントが提供されます。
タスク マネージャーを起動し、[プロセス] タブに移動します。IIS ワーカー プロセスは別のユーザー アカウントで実行されるため、[すべてのユーザーのプロセスを表示する] をオンにする必要があります。 w3wp.exe サーバー ワーカー プロセスのサイズに注意してください。
"図 1: IIS ワーカー プロセスを示すタスク マネージャー"次に、以下のコマンド ラインを実行します。
TASKLIST /fi "imagename eq w3wp.exe" /m
ワーカー プロセスによって 90 を超える DLL が読み込まれていることがわかります。 そのほとんどが \intersrv\ ディレクトリにあります。これらの多くは、<globalModules> セクションを調べたときに最初のタスクで確認したモジュール DLL で、.NET フレームワークとサーバー ランタイム自体をサポートするその他のものがいくつかあります。
サーバーを取り除く
前のタスクでは、サーバーによって読み込まれるコンポーネントの既定の一覧を調べました。それには、認証から静的ファイル サービスまで、さまざまなサービスを提供する 35 を超えるモジュールが含まれていました。 サーバーに読み込まれる各コンポーネントは、サーバー フットプリント、攻撃対象領域、ランタイム パフォーマンスおよびもちろん有効な機能セットに影響します。
次のタスクで必要な機能のみを使用して独自のカスタム サーバーを構築する前に、すべてのモジュールを削除して空のサーバーを実行することで、高速の小規模で安全な Web サーバーを構築します。
前のタスクで applicationHost.config ファイルを変更した場合は、コマンド ラインから %windir%\system32\inetsrv\appcmd restore backup initial
を実行して元の状態に復元できます。
次に、サーバーを取り除きます。
テキスト エディターを使用して
%windir%\system32\inetsrv\config\applicationHost.config
を開きます。<system.webServer>/<globalModules>
セクションに移動します。空のセクション定義のみが残るように、コレクション内のすべてのエントリを削除します。
<globalModules> <!—Remove Everything --> </globalModules>
後で使用するために、スクラッチ メモ帳ウィンドウに項目を貼り付けます。 <system.webServer>/<modules> セクションでも同じ操作を繰り返します。 このセクションのすべてのエントリを削除し、後で使用するためにスクラッチ メモ帳に貼り付けます。 これにより確実に、もう読み込まないモジュールを有効にできなくなります。 後で使用するために、これらの切り取った項目をスクラッチ メモ帳ウィンドウに貼り付けます。
<system.webServer>/<handlers>
セクションでも同じ操作を繰り返します。 このセクションのすべてのエントリを削除して、無効にしたモジュールでハンドラー マッピングが指定されていないことを確認します。 後で使用するために、スクラッチ メモ帳に項目を貼り付けます。 applicationHost.config ファイルを保存して、変更を反映します。
取り除いたサーバーのフットプリントを確認する
この時点で、取り除いたサーバーを読み込む準備ができました。前の手順を繰り返して、サーバーの新しいフットプリントを調べます。
Internet Explorer を開き、次の URL を指定して Enter キーを押してサーバーに要求を行います。
http://localhost/iisstart.htm
これによりサーバー アプリケーション プールが開始され、ブラウザーにエラーが返されるはずです。これは、要求したリソースを処理するハンドラーが登録されていないためです。
タスク マネージャーを実行し、[プロセス] タブに移動します。w3wp.exe サーバー ワーカー プロセスのサイズに注意してください。
次のコマンド ラインを実行します。
TASKLIST /fi "imagename eq w3wp.exe" /m
サーバーのフットプリントが約 8 Mb に減っていることを確認します。 サーバーの時間枠では、空のサーバーのフットプリントがさらに減少します。
90 以上のものと比較して、読み込まれる DLL は 50 個だけです。これは、サーバーによってモジュール DLL が読み込まれなかったことを示し、DLL カウントの違いが直接的および間接的に考慮されています。 サービスがサーバーで無効になっているだけでなく、これらの機能のコードもプロセスに読み込まれません。 最適化後、空のサーバーの DLL 数は大幅に少なくなります。
次のタスクでは、必要な機能のみを使用してカスタム サーバーを構築します。
カスタム サーバーの構築
前のタスクでは、コア サーバー エンジンのみが実行され、追加のモジュールが読み込まれない、最小限の構成になるまでサーバーを取り除きました。 次に、企業ネットワーク上の Web ファイル サーバーとして使用するカスタム サーバーを構築します。 これを行うには、サーバーで次のサービスのみを提供できるようにします。
- 静的ファイルの提供
- ディレクトリの一覧を提供する
- 基本認証と URL ベースの承認規則を使用してコンテンツを保護する
サーバーで静的ファイルを提供できるようにする
このタスクを実行する場合、前のタスクに従い、実行中のすべてのモジュールを削除してサーバーを取り除いたと見なされます。 この状態では、サーバーによって常にすべての要求に対して空の 401 エラー応答が返されます。これは、あらゆる種類の要求処理を提供するモジュールがまったく読み込まれていないためです。
テキスト エディターを使用して
%windir%\system32\inetsrv\config\applicationHost.config
を開きます。<system.webServer>/<globalModules> セクションに移動します。 コレクション内で以下の太字の 2 行を追加します。前に使用したスクラッチ パッドからコピーして、既定のコレクション項目を保存します。 これにより、静的ファイルの要求処理を担当する静的ファイル ハンドラー モジュールと、要求の既定の認証トークンを生成する匿名認証モジュールが読み込まれます。
<globalModules> <add name="StaticFileModule" image="%windir%\System32\inetsrv\static.dll" /> <add name="AnonymousAuthenticationModule" image="%windir%\System32\inetsrv\authanon.dll" /> </globalModules>
<system.webServer>/<modules> セクションに移動します。 以下の太字の行を追加して、静的ファイル ハンドラーと匿名認証モードを有効にします。
<modules> <add name="AnonymousAuthenticationModule" /> <add name="StaticFileModule" /> </modules>
<system.webServer>/<handlers> セクションに移動します。 以下の太字の行を追加して、静的ファイル ハンドラーをすべてのファイル要求にマップします。
<handlers> <add name="StaticFile" path="*" verb="GET,HEAD" modules="StaticFileModule" resourceType="Either" requireAccess="Read"/> </handlers>
applicationHost.config ファイルを保存します。
Internet Explorer を開き、次の URL に要求を行います。
http://localhost/iisstart.htm
これにより、要求されたドキュメントが提供されます。 サーバーで静的ファイル提供機能が正常に有効になりました。
次に、以下の URL に要求を行って、ディレクトリの一覧を要求します。
http://localhost
現在、読み込まれて有効になっており、プロセス ディレクトリの一覧にマップされているハンドラーがないため、空の応答を受け取ります。つまり、空の応答が送信されます (200 OK)。 次のタスクでは、ハンドラーを追加します。
サーバーでディレクトリ一覧を提供できるようにする
このタスクを実行する場合、前のタスクを実行し、サーバーがなくなるまで取り除き、ファイル提供機能を追加したと見なされます。
テキスト エディターを使用して
%windir%\system32\inetsrv\config\applicationHost.config
を開きます。前と同様に、以下の構成を追加してディレクトリ参照モジュールを有効にし、ディレクトリ要求を処理するようにマップします (累積構成は、前の手順に基づいて、この手順の後に以下で指定されたとおりに表示されます)。
<globalModules> <add name="AnonymousAuthenticationModule" image="%windir%\system32\inetsrv\authanon.dll" /> <add name="StaticFileModule" image="%windir%\system32\inetsrv\static.dll" /> <add name="DirectoryListingModule" image="%windir%\System32\inetsrv\dirlist.dll" /> </globalModules> <modules> <add name="AnonymousAuthenticationModule" /> <add name="StaticFileModule" /> <add name="DirectoryListingModule" /> </modules> <handlers> <add name="StaticFile" path="*" verb="GET,HEAD" modules="StaticFileModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" /> </handlers>
この時点で、サーバーでディレクトリ一覧機能が有効になりました。 しかし、この機能では、セキュリティ上の理由から、ディレクトリ一覧を許可するかどうかを制御する追加の構成が公開されます。 この構成は、<system.webServer>/<directoryBrowse> セクションで指定されます。
エントリを <directoryBrowse enabled="true" /> に変更します
applicationHost.config ファイルを保存します。
Internet Explorer を開き、次の URL を要求してディレクトリへの要求を繰り返します。
http://localhost
これにより、要求されたディレクトリの一覧が提供されます。 サーバーでディレクトリ一覧機能が正常に有効になりました。
次に、認証および承認サービスを追加して、サーバー上のコンテンツを未承認のアクセスから保護します。
URL 承認によるリソースの保護
このタスクを実行する場合、前のタスクに従い、サーバーがなくなるまで取り除き、ファイル提供およびディレクトリ一覧の機能を追加したと見なされます。
テキスト エディターを使用して
%windir%\system32\inetsrv\config\applicationHost.config
を開きます。今回は、次の 2 つのモジュールを追加します。
- サーバーの Windows 資格情報に対する http1.1 経由の基本認証スキームをサポートする基本認証モジュール
- ユーザーおよびロール ルール ベースのアクセス制御をサポートする URL 承認モジュール
これらのモジュールを追加するには、モジュールの読み込みエントリを <system.webServer>/<globalModules> セクションに追加し、静的ファイル ハンドラーとディレクトリ ブラウザーで前に行ったように、<system.webServer>/<modules> セクションでモジュールを有効にします。
Note
今回は、<system.webServer>/<handlers> セクションに何も追加する必要はありません。これらのモジュールでは、要求処理が提供されず、すべての要求に対して要求サービスのみが提供されるためです。 太字で以下の項目を追加した後の最終的な構成はこのようになります。
<globalModules> <add name="AnonymousAuthenticationModule" image="%windir%\system32\inetsrv\authanon.dll" /> <add name="StaticFileModule" image="%windir%\system32\inetsrv\static.dll" /> <add name="DirectoryListingModule" image="%windir%\system32\inetsrv\dirlist.dll" /> <add name="UrlAuthorizationModule" image="%windir%\System32\inetsrv\urlauthz.dll" /> <add name="BasicAuthenticationModule" image="%windir%\System32\inetsrv\authbas.dll" /> </globalModules> <modules> <add name="AnonymousAuthenticationModule" /> <add name="StaticFileModule" /> <add name="DirectoryListingModule" /> <add name="BasicAuthenticationModule" /> <add name="UrlAuthorizationModule" /> </modules>
追加された機能を使用するには、それらを構成する必要があります。
基本認証サービスを有効にします。 <basicAuthentication> 要素に移動し、enabled 属性を true に設定します。
<basicAuthentication enabled="true" />
匿名認証を無効にします。 <anonymousAuthentication> 要素に移動し、enabled 属性を false に設定します。
<anonymousAuthentication enabled="false" userName="IUSR" />
これにより匿名認証が無効になり、アクセスが許可される前に基本認証モジュールでユーザーの認証が正常に行われる必要があります。
applicationHost.config ファイルを保存します。
Internet Explorer を開き、次の URL を要求してディレクトリへの要求を繰り返します。
http://localhost
これにより、ディレクトリの一覧が要求されます。 ブラウザーで認証を行っていないため、URL 承認モジュールによって要求が拒否されます。 基本認証モジュールによって、拒否がインターセプトされ、基本認証チャレンジがブラウザーにトリガーされ、これによりブラウザーに基本認証ログイン ダイアログが表示されます。
無効な資格情報でログインします。 要求は拒否され、再度、資格情報の入力が求められます。
コンピューターへのログインに使用した管理者アカウントでログインします。 サーバーに認証と承認の機能が正常に追加されたことを示すディレクトリの一覧が表示されます。
まとめ
この記事では、サーバーのコンポーネント化された性質について説明し、提供される IIS 機能を調べ、ユーザーが必要とする可能性があるサービスのみを使用してカスタム Web サーバーを構築する方法について説明しました。
サーバーを再度使用する前に、このチュートリアルの一部として実行されたサーバー構成の変更を元に戻します。 前にバックアップを作成した場合は、コマンド ラインから %windir%\system32\inetsrv\appcmd restore backup initial
を実行して復元します。
関連リンク
詳細については、次のリンクを参照してください。
- IIS コア アーキテクチャの詳細については、IIS.NET の IIS 7.0 以降の Core Web Server に関するセクションを参照してください。
- IIS モジュールの詳細については、IIS の 7.0 以降のモジュールの概要に関するページを参照してください。
- IIS 機能を拡張または置き換えるモジュールの構築の詳細については、「.NET を使用したモジュールの開発」およびネイティブ (C/C++) モジュールの開発に関するページを参照してください。