セキュリティ保護された ASP.NET アプリケーションの構築 : 認証、認定、および通信のセキュリティ保護 ASP.NET からのクライアント証明書を使用して Web サービスを呼び出す方法
J.D. Meier, Alex Mackman, Michael Dunner, and Srinath Vasireddy
Microsoft Corporation
November 2002
日本語版最終更新日 2003 年 3 月 17 日
Microsoft® ASP.NET
Microsoft Visual Studio® .NET
全体の概要については、「セキュリティ保護された ASP.NET アプリケーションの構築」の開始ページを参照してください。
要約 : Web サービスは、クライアント証明書を使ってクライアント アプリケーションを認証することができます。ここでは、クライアント証明書で認証を行う Web サービスを設定する方法、および ASP.NET Web アプリケーションの証明書を渡して Web サービスを呼び出す方法について説明します。
目次
サービス コンポーネントを使用する理由
ユーザー プロファイルが必要な理由
必要条件
要約
関連資料
Web サービスが、認定を行うために呼び出し側 (他のアプリケーション) を認証する必要が出てくることはよくあります。クライアント証明書は、Web サービスに優れた認証メカニズムを提供します。また、この証明書は使用中のアプリケーションにとっても役立っており、これを使用することでクライアント アプリケーションと Web サービスとの間に作成された安全な通信チャネル (SSL : Secure Sockets Layer を利用) を使って、Web サービスとの機密情報のやり取りを安全に行うことができます。SSL によりメッセージの整合性と機密性が確保されます。
ここでは、クライアント証明書を要求するように設定された Web サービスを呼び出す方法について説明します。
メモ ここで取り上げる情報は、ASP.NET および IIS がホストするリモート コンポーネントにも適用されます。
サービス コンポーネントを使用する理由
ここで紹介するソリューションは、独自のサービス アカウントを使用して、Enterprise Services サーバー アプリケーションで実行するように設定されているサービス コンポーネントを使用しています。ASP.NET Web アプリケーションは、クライアント証明書を渡して Web サービスへの呼び出しを行うサービス コンポーネントを呼び出します。このソリューションの構成を図 1 に示します。
図 1 ASP.NET はサービス コンポーネントを呼び出して Web サービスを起動
この構成によって、システムは Web サービスと通信するときに確実にユーザー プロファイルにアクセスできるようになります。これは初めて SSL ハンドシェイクが発生するときに必要です。
メモ Web アプリケーションを実行するときに使用する ASPNET アカウントには、"対話的なログオンを拒否する" 特権が設定されています。つまり、このアカウントでは対話的にログオンすることができません。したがって、このアカウントにはユーザー プロファイルが登録されていません。
ASPNET アカウントを含め Web アプリケーションの実行に使用するアカウントには対話型ログオン機能を付与しないでください。また、Web アプリケーションを実行するためのアカウントを設定するときは、必要最低限の特権のみを与えるようにします。詳細については、このガイドの「パート IV : 参照」の「ASP.NET の実行に使用するカスタム アカウントの作成方法」を参照してください。
ユーザー プロファイルが必要な理由
クライアント証明書を必要とする Web サービスへの要求を行うと、クライアントとサーバー間で SSL ハンドシェイクが発生します。ここで交換されるコンポーネントには、サーバー証明書、クライアント証明書、およびクライアントによって生成される "プリマスタ シークレット" などがあります。このシークレットは後でプロトコルで使用され、"マスタ シークレット" を生成します。
証明書の提示元が本当に秘密キーの保有者かどうかをサーバーが確認できるように、クライアントはプリマスタ シークレットを秘密キーで暗号化し、その暗号化されたプリマスタ シークレットをサーバーに送信する必要があります。システムがクライアントの秘密キーにアクセスしてプリマスタ シークレットに署名するには、クライアントのキー ストアから秘密キーにアクセスしなければなりません。キー ストアはクライアント プロファイル内にあり、このクライアント プロファイルは読み込む必要があります。
必要条件
ハードウェア、ソフトウェア、ネットワーク インフラストラクチャ、スキル、知識、サービス パックの要件としては、次のものが必要です。
- Microsoft® Windows® 2000 オペレーティング システム
- Microsoft Visual Studio® .NET 開発システム
- 証明機関 (CA) へのアクセス (新しい証明書を生成するために必要)
- サーバー証明書がインストールされている Web サーバー
Web サーバー証明書のインストールの詳細については、「Web サーバー上で SSL を設定する方法」を参照してください。
また、Microsoft Visual C#® 開発ツールの知識も必要です。
要約
ここでは、次の手順について説明します。
- シンプルな Web サービスを作成する。
- クライアント証明書を必要とする Web サービス仮想ディレクトリを構成する。
- サービス コンポーネントを実行するためのカスタム アカウントを作成する。
- カスタム アカウントのクライアント証明書を要求する。
- ブラウザを使用してクライアント証明書をテストする。
- クライアント証明書をファイルにエクスポートする。
- Web サービスを呼び出すときに使用するサービス コンポーネントを開発する。
- サービス コンポーネントを設定およびインストールする。
- Web アプリケーションを開発して、サービス コンポーネントを呼び出す。
メモ ここでは、Web サービスをホストする Web サービス コンピュータ には "WSServer"、クライアント ASP.NET Web アプリケーションおよびサービス コンポーネントをホストする Web サービス クライアント コンピュータには "WSClient" という名前が付けられています。
1. シンプルな Web サービスを作成する
■ Web サービス ホスト コンピュータにシンプルな Web サービスを作成するには
- Visual Studio .NET を起動して、"SecureMath" という名前の新しい C# ASP.NET Web サービス アプリケーションを作成します。
- service1.asmx の名前を math.asmx に変更します。
- math.asmx.cs を開き、"Service1" を "math" に変更します。
- 次の Web メソッドを math クラスに追加します。
[WebMethod]
public long Add(long operand1, long operand2)
{
return (operand1 + operand2);
}
- [ビルド] メニューの [ソリューションのビルド] をクリックして、Web サービスを作成します。
2. クライアント証明書を必要とする Web サービス仮想ディレクトリを構成する
ここでは、インターネット インフォメーション サービスを使用して、証明書を必要とする SSL 用 Web サービス仮想ディレクトリを設定します。
この手順は有効な証明書が Web サーバーにインストールされていることを想定しています。Web サーバー証明書のインストールの詳細については、このガイドの「パート IV : 参照」の「Web サーバー上で SSL を設定する方法」を参照してください。
■ クライアント証明書を必要とする Web サービス 仮想ディレクトリを構成するには
Web サービスのホスト コンピュータでインターネット インフォメーション サービスを起動します。
SecureMath 仮想ディレクトリに移動します。
[SecureMath] を右クリックし、[プロパティ] をクリックします。
[ディレクトリのセキュリティ] タブをクリックします。
[セキュリティ保護された通信] の [編集] をクリックします。
[編集] ボタンをクリックできない場合は、Web サーバー証明書がインストールされていない可能性があります。
[保護されたチャンネル (SSL) を要求する] チェック ボックスをオンにします。
[クライアント証明書を要求する] をクリックします。
[OK] をクリックし、もう一度 [OK] をクリックします。
[継承/優先] ダイアログ ボックスで [すべて選択] をクリックします。次に、[OK] をクリックして [SecureMath のプロパティ] ダイアログ ボックスを閉じます。
これにより、仮想ディレクトリのルート内にあるすべてのサブディレクトリに対して、新しいセキュリティ設定が適用されます。
3. サービス コンポーネントを実行するためのカスタム アカウントを作成する
ここでは、Web サービスを呼び出すサービス コンポーネントを実行するときに使用するユーザー アカウントを、Web サービス クライアント コンピュータに新しく作成します。
■ サービス コンポーネントを実行するためのカスタム アカウントを作成するには
クライアント コンピュータ上で、強力なパスワードを持つ新しいユーザー アカウントを作成します。[ユーザーは次回ログオン時にパスワードの変更が必要] チェック ボックスをオフにし、[パスワードを無期限にする] チェック ボックスをオンにします。
このアカウントを [Administrators] グループに追加します。
ユーザー プロファイルを読み込むために使用するアカウントは、そのローカル コンピュータの管理者である必要があります。
4. カスタム アカウントのクライアント証明書を要求する
ここでは、まず、新しいカスタム アカウントを使用してクライアント コンピュータにログオンします。そして、証明書に対する要求を発行します。この手順は、Microsoft 証明書サービスを使用していることを想定しています。Microsoft 証明書サービスを使用しないで新しい証明書を作成した場合は、カスタム アカウントを使用してログオンしながら、使用している CA に対してクライアント証明書の要求を発行し、その証明書をインストールします。
また、証明書要求に対する応答として証明書を自動発行するよう Microsoft 証明書サービスが設定されていることも前提になっています。要求を保留にするよう証明書サービスを設定することも可能です。要求を保留にすると、管理者が明示的に証明書を発行する必要があります。
■ Microsoft 証明書サービスの設定を確認するには
Microsoft 証明書サービスを実行しているコンピュータで、[管理ツール] の [証明機関] をクリックします。
[証明機関 (ローカル)] を展開し、証明機関を右クリックして [プロパティ] をクリックします。
[ポリシー モジュール] タブをクリックし、[構成] をクリックします。
既定の動作を確認します。
次の手順では、[常に証明書を発行する] チェック ボックスがオンになっていることを前提としています。
■ カスタム アカウントのクライアント証明書を要求するには
クライアント コンピュータからログオフし、カスタム アカウントを使用して再びログオンします。
これにより、カスタム アカウントのユーザー プロファイルが強制的に作成されます。
クライアント証明書を要求するために CA を参照します。たとえば、CA が CAServer コンピュータ上に配置されている場合は、次の場所を参照します。
http://caserver/certsrv
[証明書の要求] をクリックし、[次へ] をクリックします。
ユーザー証明書が選択されていることを確認して、[次へ] をクリックします。
[送信] をクリックします。
要求が生成され、処理を行うために CA に送信されます。
証明書が発行され CA サーバーからの応答を受信したら、[この証明書のインストール] をクリックします。
その CA の証明書がローカル コンピュータの信頼できるルート証明機関としてインストールされたことを確認します。
これを確認するには、次の手順を実行します。
- タスク バーの [スタート] ボタンをクリックし、[ファイル名を指定して実行] をクリックします。
- 「mmc」と入力し、[OK] をクリックします。
- [コンソール] メニューの [スナップインの追加と削除] をクリックします。
- [追加] をクリックします。
- [証明書] をクリックし、次に [追加] をクリックします。
- [コンピュータ アカウント] をクリックし、[次へ] をクリックします。
- [ローカル コンピュータ (このコンソールを実行しているコンピュータ)] をクリックし、[完了] をクリックします。
- [閉じる] をクリックし、[OK] をクリックします。
- MMC スナップインの左側のペインで、[証明書 (ローカル コンピュータ)] を展開します。
- [信頼されたルート証明機関] を展開し、[証明書] をクリックします。
- CA の証明書が一覧にあることを確認します。
CA の証明書が一覧にない場合は、以下の手順を実行します。
- http://caserver/certsrv を参照します。
- [CA 証明書または証明書失効リストの取得] をクリックし、[次へ] をクリックします。
- [この CA 証明書のパスをインストールしてください。] をクリックします。
5. ブラウザを使用してクライアント証明書をテストする
ここでは、Web サービスを参照して、サーバーまたはクライアント証明書のいずれかに問題が発生していないかどうかを確認します。
■ ブラウザを使用してクライアント証明書をテストするには
Internet Explorer を使用して、https://server/SecureMath/Math.asmx に移動します。
このサイトは SSL を要求するよう構成されているため、必ず "https" を指定するようにしてください。
[クライアントの認証] ダイアログ ボックスが表示されたら、自分のクライアント証明書をクリックして、[OK] をクリックします。
Web サービスのテスト ページがブラウザに正常に表示されるかどうか確認します。
下の図 1 のようなダイアログ ボックスが表示された場合は、前の手順で説明したように証明機関の証明書を [信頼されたルート証明機関] ストアにインストールする必要があります。
図 1 [セキュリティの警告] ダイアログ ボックス
6. クライアント証明書をファイルにエクスポートする
ここでは、クライアント証明書をファイルにエクスポートします。後でこのクライアント証明書を Web サービスに渡す必要が出てきたとき、サービス コンポーネントがこれを取り出します。
■ クライアント証明書をファイルにエクスポートするには
Internet Explorer で、[ツール] メニューの [インターネット オプション] をクリックします。
[コンテンツ] タブをクリックします。
[証明書] をクリックします。
クライアント証明書をクリックし、[エクスポート] をクリックします。
[証明書のエクスポート ウィザード] ダイアログ ボックスで [次へ] をクリックします。
[いいえ、秘密キーをエクスポートしません] が選択されていることを確認し、[次へ] をクリックします。
[DER encoded binary X.509 (.CER)] が選択されていることを確認し、[次へ] をクリックします。
.NET Framework では Base-64 または PKCS #7 形式をサポートしていないため、必ずこの形式を使用してください。
エクスポート ファイル名を入力します。以降の手順で .cer エクスポート ファイルの場所が必要になるので、これをメモしておきます。
[次へ] をクリックし、[完了] をクリックして、証明書をエクスポートします。
Internet Explorer を閉じます。
コンピュータからログオフし、通常の開発に使用しているアカウントで再びログオンします。
7. Web サービスを呼び出すときに使用するサービス コンポーネントを開発する
ここでは、C# クラス ライブラリ アプリケーションを新しく作成し、Web サービスを呼び出すときに使用するサービス コンポーネントを作成します。この手順は、ユーザーがクライアント コンピュータで作業していることを前提としています。
■ Web サービスを呼び出すときに使用するサービス コンポーネントを開発するには
Visual Studio .NET を起動して、"WebServiceRequestor" という名前の新しい C# クラス ライブラリを作成します。
SecureMath Web サービスへの Web 参照を追加します。
重要 Web 参照を追加する場合は、クライアント証明書を使用する必要がないように (ただし、SSL については引き続き必要とするように)、Web サービス仮想ディレクトリの設定を一時的に変更しておく必要があります。Web 参照を正常に追加できたら、クライアント証明書を必要とするよう仮想ディレクトリの設定を元に戻します。
サイトにクライアント証明書が必要な場合、実際には、サービスの発行側が個別のオフライン ファイルとして WSDL を利用できるように設定し、サービスの利用側はこれを使用してプロキシを作成します。
[Web 参照の追加] ダイアログ ボックスで Web サービスの場所を指定するときは必ず "https" を指定するようにしてください。これを指定しないとエラーが発生します。Web サービスの仮想ディレクトリは SSL を要求するように構成されているからです。
System.EnterpriseServices アセンブリへの参照を追加します。
class1.cs の名前を ProfileManager.cs に変更します。
ProfileManager.cs に以下のクラス定義を追加します (骨組みとなる class1 クラスと置き換えてください)。ProfileManager クラスは P/Invoke を使用して LoadUserProfile Win32 API および UnloadUserProfile Win32 API を呼び出しています。
internal class ProfileManager { [DllImport("Userenv.dll", SetLastError=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)] internal static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo); [DllImport("Userenv.dll", SetLastError=true, CharSet=System.Runtime.InteropServices.CharSet.Auto)] internal static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] public struct PROFILEINFO { public int dwSize; public int dwFlags; public String lpUserName; public String lpProfilePath; public String lpDefaultPath; public String lpServerName; public String lpPolicyPath; public IntPtr hProfile; } }
プロジェクトに 2 番目のクラス ファイルとして MathServiceComponent.cs を追加します。
MathServiceComponent.cs の既存の using ステートメントの下に、次の using ステートメントを追加します。
using System.Net;
using System.Web.Services;
using System.Security.Principal;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using WebServiceRequestor.WebReference1;
次のクラス定義を追加します。これにより、CallMathWebService パブリック メソッドが提供されます。後の手順で、クライアント ASP.NET Web アプリケーションからこのメソッドを呼び出します。
// This class calls the web service that requires a certificate. public class MathServiceComponent : ServicedComponent { [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] private extern static bool CloseHandle(IntPtr handle); // Calls the Web service that requires client certificates // certFilepath points to the .cer file to use // url is the Web service url // operand1 and operand2 are the parameters to pass to the Web service public long CallMathWebService(String certFilepath, String url, int operand1, int operand2) { bool retVal = false; // Need to duplicate the token. LoadUserProfile needs a token with // TOKEN_IMPERSONATE and TOKEN_DUPLICATE. const int SecurityImpersonation = 2; IntPtr dupeTokenHandle = DupeToken(WindowsIdentity.GetCurrent().Token, SecurityImpersonation); if(IntPtr.Zero == dupeTokenHandle) { throw new Exception("Unable to duplicate token."); } // Load the profile. ProfileManager.PROFILEINFO profile = new ProfileManager.PROFILEINFO(); profile.dwSize = 32; profile.lpUserName = @"alexmlaptop\CustomASPNET"; retVal = ProfileManager.LoadUserProfile(dupeTokenHandle, ref profile); if(false == retVal) { throw new Exception("Error loading user profile. " + Marshal.GetLastWin32Error()); } // Instantiate the Web service proxy math mathservice = new math(); mathservice.Url = url; String certPath = certFilepath; mathservice.ClientCertificates.Add( X509Certificate.CreateFromCertFile(certPath)); long lngResult = 0; try { lngResult = mathservice.Add(operand1, operand2); } catch(Exception ex) { if(ex is WebException) { WebException we = ex as WebException; WebResponse webResponse = we.Response; throw new Exception("Exception calling method. " + ex.Message); } } ProfileManager.UnloadUserProfile(WindowsIdentity.GetCurrent().Token, profile.hProfile); CloseHandle(dupeTokenHandle); return lngResult; } private IntPtr DupeToken(IntPtr token, int Level) { IntPtr dupeTokenHandle = new IntPtr(0); bool retVal = DuplicateToken(token, Level, ref dupeTokenHandle); if (false == retVal) { return IntPtr.Zero; } return dupeTokenHandle; } } // end class
[ビルド] メニューの [ソリューションのビルド] をクリックします。
8. サービス コンポーネントを設定およびインストールする
ここでは、サービス コンポーネントを設定して厳密名を付け、それをグローバル アセンブリ キャッシュにインストールし、COM+ に登録します。
- assemblyinfo.cs を開き、次の using ステートメントを既存の using ステートメントの下に追加します。
using System.EnterpriseServices;
- assemblyinfo.cs に次のアセンブリ レベルの属性を追加して、COM+ サーバー アプリケーション内で実行するサービス コンポーネントを構成します。
[assembly: ApplicationActivation(ActivationOption.Server)]
コマンド プロンプト ウィンドウを開き、現在のプロジェクトのディレクトリに移動します。
sn.exe ユーティリティを使用して、公開キーと秘密キーのペアを格納するキー ファイルを生成します。
sn.exe -k WebServiceRequestor.snk
Visual Studio .NET に戻ります。
assemblyinfo.cs 内で [AssembleKeyFile] 属性を探し、プロジェクト ディレクトリ内でキー ファイルの参照を行うよう次のように変更します。
[assembly: AssemblyKeyFile(@"..\..\WebServiceRequestor.snk")]
[ビルド] メニューの [ソリューションのビルド] をクリックします。
コマンド プロンプトに戻り、次のコマンドを実行します。アセンブリがグローバル アセンブリ キャッシュに追加されます。
gacutil.exe /i bin\debug\webservicerequestor.dll
- 次のコマンドを実行してこのアセンブリを COM+ に登録します。
regsvcs bin\debug\webservicerequestor.dll
[管理ツール] の [コンポーネント サービス] を起動します。
[コンポーネント サービス]、[コンピュータ]、[マイ コンピュータ] の順に展開します。
[COM+ アプリケーション] フォルダを展開します。
[WebServiceRequestor] を右クリックし、[プロパティ] をクリックします。
[ID] タブをクリックします。
[このユーザー] をクリックし、作成済みのカスタム アカウントのアカウントの詳細を入力します。
これにより、COM+ アプリケーションを実行するときはカスタム アカウントを使用するように構成されます。
[OK] をクリックして、[プロパティ] ダイアログ ボックスを閉じます。
コンポーネント サービスを閉じます。
9. Web アプリケーションを開発して、サービス コンポーネントを呼び出す
ここでは、シンプルな ASP.NET Web アプリケーションを作成します。このアプリケーションをクライアント アプリケーションとして使用し、サービス コンポーネント経由で Web サービスを呼び出します。
■ Web アプリケーションを開発して、サービス コンポーネントを呼び出すには
Web サービス クライアント コンピュータ上で、"SecureMathClient" という名前の新しい C# ASP.NET Web アプリケーションを作成します。
System.EnterpriseServices への参照を追加します。
WebServiceRequestor サービス コンポーネントへの参照を追加します。
WebServiceRequestor プロジェクト ディレクトリの bin\debug フォルダ内にある WebServiceRequestor.dll を参照します。
WebForm1.aspx.cs を開き、次の using ステートメントを既存の using ステートメントの下に追加します。
using WebServiceRequestor;
デザイナ モードで WebForm1.aspx を表示し、図 2 で示すように次の ID を使用したフォームを作成します。
オペランド 1
オペランド 2
結果
追加
図 3 Web フォーム コントロールの配置
[追加] ボタンをダブルクリックして、ボタン クリック イベント ハンドラを作成します。
そのイベント ハンドラに次のコードを追加します。
メモ 「6. クライアント証明書をファイルにエクスポートする」でエクスポートした証明書ファイルの場所を certPath 文字列にセットします。
url 文字列は Web サービスの HTTPS URL にセットします。
private void add_Click(object sender, System.EventArgs e)
{
// TODO: Replace with a valid path to your certificate
string certPath = @"C:\CustomAccountCert.cer";
// TODO: Replace with a valid URL to your Web service
string url = "https://wsserver/securemath/math.asmx";
MathServiceComponent mathComp = new MathServiceComponent();
long addResult = mathComp.CallMathWebService( certPath,
url,
Int32.Parse(operand1.Text),
Int32.Parse(operand2.Text));
result.Text = addResult.ToString();
}
[ビルド] メニューの [ソリューションのビルド] をクリックします。
アプリケーションを実行します。追加する 2 つの数字を入力し、[追加] をクリックします。
Web アプリケーションがサービス コンポーネントを呼び出します。これにより、SSL を使用してクライアント証明書を渡す Web サービスが呼び出されます。
関連資料
詳細については、このガイドの「パート IV : 参照」の「Web サーバー上で SSL を設定する方法」を参照してください。