WCF セキュリティのプログラミング
このトピックでは、セキュリティで保護された Windows Communication Foundation (WCF) アプリケーションの作成に使用される基本的なプログラミング タスクについて説明します。 ここでは、転送セキュリティと総称される認証、機密性、および整合性についてのみ説明します。 承認 (リソースまたはサービスへのアクセスの制御) についての説明は含まれません。承認の詳細については、承認に関するページを参照してください。
Note
セキュリティの概念、特に WCF に関するセキュリティの概念については、MSDN の「Web サービス拡張 (WSE) 3.0 のシナリオ、パターン、および実装のガイダンス」にある patterns & practices の一連のチュートリアルを参照してください。
WCF セキュリティのプログラミングは、セキュリティ モードの設定、クライアント資格情報の種類の設定、および資格情報の値の設定の 3 つの手順に基づいています。 これらの手順は、コードまたは構成を使用して実行できます。
セキュリティ モードの設定
WCF のセキュリティ モードに関する一般的なプログラミング手順は、次のとおりです。
アプリケーション要件を満たす適切な定義済みバインディングを選択します。 バインディングの選択肢の一覧については、「システム指定のバインディング」を参照してください。 既定では、ほとんどのバインディングでセキュリティが有効になっています。 唯一の例外は、BasicHttpBinding クラス (構成を使用する場合は、<basicHttpBinding>) です。
選択するバインディングによってトランスポートが決まります。 たとえば、WSHttpBinding はトランスポートとして HTTP を使用し、NetTcpBinding は TCP を使用します。
バインディングのセキュリティ モードを選択します。 選択したバインディングによって、選択できるモードが決まります。 たとえば、WSDualHttpBinding を選択すると、トランスポート セキュリティを使用できません (このオプションはありません)。 同様に、MsmqIntegrationBinding や NetNamedPipeBinding を選択すると、メッセージ セキュリティを使用できません。
次の 3 つの選択肢があります。
Transport
トランスポート セキュリティは、選択したバインディングが使用する機構に依存します。 たとえば、
WSHttpBinding
を使用している場合、セキュリティ機構は SSL (Secure Sockets Layer) です (これは、HTTPS プロトコルの機構でもあります)。 一般に、トランスポート セキュリティの主な利点は、使用するトランスポートに関係なく、優れたスループットが得られることです。 ただし、制限が 2 つあります。1 つは、ユーザーの認証に使用する資格情報の種類がトランスポート機構によって決まることです。 これは、異なる種類の資格情報を要求する他のサービスと相互運用する必要がある場合には不都合です。 もう 1 つの制限は、メッセージ レベルでセキュリティが適用されないため、エンド ツー エンドではなく、ホップ単位でセキュリティが実装されることです。 この 2 つ目の制限は、クライアントとサービス間のメッセージ パスに中継局が含まれている場合にのみ問題になります。 使用するトランスポートに関する詳細については、「トランスポートの選択」を参照してください。 トランスポート セキュリティの使用の詳細については、「トランスポート セキュリティの概要」を参照してください。Message
メッセージ セキュリティでは、メッセージの安全性を維持するために必要なヘッダーとデータがすべてのメッセージに含まれます。 ヘッダーの構成は変更可能であるため、任意の数の資格情報を含めることができます。 トランスポート機構で提供できない特殊な資格情報の種類を要求する他のサービスと相互運用している場合や、メッセージを複数のサービスで使用する必要があり、各サービスが異なる資格情報の種類を要求する場合には、これは重要な要素になります。
詳細については、メッセージのセキュリティに関するページをご覧ください。
TransportWithMessageCredential
このモードを選択すると、トランスポート層を使用してメッセージの転送がセキュリティで保護されると同時に、他のサービスが必要とするさまざまな資格情報がすべてのメッセージに含まれます。 これにより、トランスポート セキュリティのパフォーマンス上の利点とメッセージ セキュリティの豊富な資格情報の利点の両方が提供されます。 このモードは、BasicHttpBinding、WSFederationHttpBinding、NetPeerTcpBinding、および WSHttpBinding の各バインディングで使用できます。
HTTP でトランスポート セキュリティを使用する (つまり、HTTPS を使用する) 場合は、SSL 証明書を使用してホストを構成し、ポートで SSL を有効にします。 詳細については、「HTTP トランスポート セキュリティ」を参照してください。
WSHttpBinding を使用している場合、セキュリティで保護されたセッションを確立する必要がないときは、EstablishSecurityContext プロパティを
false
に設定します。セキュリティで保護されたセッションは、クライアントとサーバーが対称キーを使用してチャネルを作成するときに発生します (メッセージ交換中、やりとりが終了するまで、クライアントとサーバーの両方が同じキーを使用します)。
クライアント資格情報の種類の設定
適切なクライアント資格情報の種類を選択します。 詳細については、「資格情報の種類の選択」を参照してください。 使用できるクライアント資格情報の種類は、次のとおりです。
Windows
Certificate
Digest
Basic
UserName
NTLM
IssuedToken
モードの設定に応じて、資格情報の種類を設定する必要があります。 たとえば、次の構成例に示すように、wsHttpBinding
を選択しており、モードを "Message" に設定した場合は、Message 要素の clientCredentialType
属性の値を None
、Windows
、UserName
、Certificate
、および IssuedToken
のいずれかに設定できます。
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="myBinding">
<security mode="Message"/>
<message clientCredentialType="Windows"/>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
または
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;
Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
サービス資格情報の値の設定
クライアント資格情報の種類を選択したら、サービスとクライアントが使用する実際の資格情報を設定する必要があります。 サービスでは、資格情報は ServiceCredentials クラスを使用して設定します。また、資格情報は Credentials クラスの ServiceHostBase プロパティによって返されます。 使用しているバインディングによって、サービス資格情報の種類、選択されるセキュリティ モード、およびクライアント資格情報の種類が暗黙的に決まります。 サービス資格情報の証明書を設定するコードを次に示します。
// Create the binding for an endpoint.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
// Create the ServiceHost for a calculator.
Uri baseUri = new Uri("net.tcp://MachineName/tcpBase");
Uri[] baseAddresses = new Uri[] { baseUri };
ServiceHost sh = new ServiceHost(typeof(Calculator), baseAddresses);
// Add an endpoint using the binding and a new address.
Type c = typeof(ICalculator);
sh.AddServiceEndpoint(c, b, "MyEndpoint");
// Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"client.com");
try
{
sh.Open();
Console.WriteLine("Listening....");
Console.ReadLine();
sh.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("A communication error occurred: {0}", ce.Message);
Console.WriteLine();
}
catch (System.Exception exc)
{
Console.WriteLine("An unforeseen error occurred: {0}", exc.Message);
Console.ReadLine();
}
' Create the binding for an endpoint.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
' Create the ServiceHost for a calculator.
Dim baseUri As New Uri("net.tcp://MachineName/tcpBase")
Dim baseAddresses() As Uri = {baseUri}
Dim sh As New ServiceHost(GetType(Calculator), baseAddresses)
' Add an endpoint using the binding and a new address.
Dim c As Type = GetType(ICalculator)
sh.AddServiceEndpoint(c, b, "MyEndpoint")
' Set a certificate as the credential for the service.
sh.Credentials.ServiceCertificate.SetCertificate( _
StoreLocation.LocalMachine, _
StoreName.My, _
X509FindType.FindBySubjectName, _
"contoso.com")
Try
sh.Open()
Console.WriteLine("Listening....")
Console.ReadLine()
sh.Close()
Catch ce As CommunicationException
Console.WriteLine("A communication error occurred: {0}", ce.Message)
Console.WriteLine()
Catch exc As System.Exception
Console.WriteLine("An unforeseen error occurred: {0}", exc.Message)
Console.ReadLine()
End Try
クライアント資格情報の値の設定
クライアントでは、クライアント資格情報の値は ClientCredentials クラスを使用して設定します。また、クライアント資格情報の値は ClientCredentials クラスの ClientBase<TChannel> プロパティから返されます。 TCP プロトコルを使用するクライアントで、資格情報として証明書を設定するコードを次に示します。
// Create a NetTcpBinding and set its security properties. The
// security mode is Message, and the client must be authenticated with
// Windows. Therefore the client must be on the same Windows domain.
NetTcpBinding b = new NetTcpBinding();
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
// Set a Type variable for use when constructing the endpoint.
Type c = typeof(ICalculator);
// Create a base address for the service.
Uri tcpBaseAddress =
new Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName");
// The base address is in an array of URI objects.
Uri[] baseAddresses = new Uri[] { tcpBaseAddress };
// Create the ServiceHost with type and base addresses.
ServiceHost sh = new ServiceHost(typeof(CalculatorClient), baseAddresses);
// Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "");
sh.Open();
string address = sh.Description.Endpoints[0].ListenUri.AbsoluteUri;
Console.WriteLine("Listening @ {0}", address);
Console.WriteLine("Press enter to close the service");
Console.ReadLine();
' Create a NetTcpBinding and set its security properties. The
' security mode is Message, and the client must be authenticated with
' Windows. Therefore the client must be on the same Windows domain.
Dim b As New NetTcpBinding()
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
' Set a Type variable for use when constructing the endpoint.
Dim c As Type = GetType(ICalculator)
' Create a base address for the service.
Dim tcpBaseAddress As New Uri("net.tcp://machineName.Domain.Contoso.com:8036/serviceName")
' The base address is in an array of URI objects.
Dim baseAddresses() As Uri = {tcpBaseAddress}
' Create the ServiceHost with type and base addresses.
Dim sh As New ServiceHost(GetType(CalculatorClient), baseAddresses)
' Add an endpoint to the service using the service type and binding.
sh.AddServiceEndpoint(c, b, "")
sh.Open()
Dim address As String = sh.Description.Endpoints(0).ListenUri.AbsoluteUri
Console.WriteLine("Listening @ {0}", address)
Console.WriteLine("Press enter to close the service")
Console.ReadLine()