WCF セキュリティのプログラミング

このトピックでは、セキュリティで保護された Windows Communication Foundation (WCF) アプリケーションを作成するために使用する基本的なセキュリティ プログラミング タスクについて説明します。ここでは、転送セキュリティと総称される認証、機密性、および整合性についてのみ説明します。承認 (リソースまたはサービスへのアクセスの制御) についての説明は含まれません。承認の詳細については、「承認」を参照してください。

ms731925.note(ja-jp,VS.100).gif注 :
セキュリティの概念、特に WCF に関するセキュリティの概念については、MSDN の「Web サービス拡張 (WSE) 3.0 のシナリオ、パターン、および実装のガイダンス」にある patterns & practices の一連のチュートリアルを参照してください。

WCF セキュリティのプログラミングは、セキュリティ モードの設定、クライアント資格情報の種類の設定、および資格情報の値の設定の 3 つの手順に基づいています。これらの手順は、コードまたは構成を使用して実行できます。

セキュリティ モードの設定

WCF のセキュリティ モードに関する一般的なプログラミング手順は、次のとおりです。

  1. アプリケーション要件を満たす適切な定義済みバインディングを選択します。バインディングの選択肢の一覧については、「システム標準のバインディング」を参照してください。既定では、ほとんどのバインディングでセキュリティが有効になっています。唯一の例外は、BasicHttpBinding クラス (構成を使用する場合は basicHttpBinding Element) です。

    選択するバインディングによってトランスポートが決まります。たとえば、WSHttpBinding はトランスポートとして HTTP を使用し、NetTcpBinding は TCP を使用します。

  2. バインディングのセキュリティ モードを選択します。選択したバインディングによって、選択できるモードが決まります。たとえば、WSDualHttpBinding を選択すると、トランスポート セキュリティを使用できません (このオプションはありません)。同様に、MsmqIntegrationBindingNetNamedPipeBinding を選択すると、メッセージ セキュリティを使用できません。

    次の 3 つの選択肢があります。

    1. Transport

      トランスポート セキュリティは、選択したバインディングが使用する機構に依存します。たとえば、WSHttpBinding を使用している場合、セキュリティ機構は SSL (Secure Sockets Layer) です (これは、HTTPS プロトコルの機構でもあります)。一般に、トランスポート セキュリティの主な利点は、使用するトランスポートに関係なく、優れたスループットが得られることです。ただし、制限が 2 つあります。1 つは、ユーザーの認証に使用する資格情報の種類がトランスポート機構によって決まることです。これは、異なる種類の資格情報を要求する他のサービスと相互運用する必要がある場合には不都合です。もう 1 つの制限は、メッセージ レベルでセキュリティが適用されないため、エンド ツー エンドではなく、ホップ単位でセキュリティが実装されることです。この 2 つ目の制限は、クライアントとサービス間のメッセージ パスに中継局が含まれている場合にのみ問題になります。使用するトランスポート詳細情報、「トランスポートの選択」を参照してください。トランスポート セキュリティの使用詳細情報、「トランスポート セキュリティの概要」を参照してください。

    2. Message

      メッセージ セキュリティでは、メッセージの安全性を維持するために必要なヘッダーとデータがすべてのメッセージに含まれます。ヘッダーの構成は変更可能であるため、任意の数の資格情報を含めることができます。トランスポート機構で提供できない特殊な資格情報の種類を要求する他のサービスと相互運用している場合や、メッセージを複数のサービスで使用する必要があり、各サービスが異なる資格情報の種類を要求する場合には、これは重要な要素になります。

      詳細については、次のトピックを参照してください。 WCF のメッセージのセキュリティ.

    3. TransportWithMessageCredential

      このモードを選択すると、トランスポート層を使用してメッセージの転送がセキュリティで保護されると同時に、他のサービスが必要とするさまざまな資格情報がすべてのメッセージに含まれます。これにより、トランスポート セキュリティのパフォーマンス上の利点とメッセージ セキュリティの豊富な資格情報の利点の両方が提供されます。このモードは、BasicHttpBindingWSFederationHttpBindingNetPeerTcpBinding、および WSHttpBinding の各バインディングで使用できます。

  3. HTTP でトランスポート セキュリティを使用する (つまり、HTTPS を使用する) 場合は、SSL 資格情報を使用してホストを構成し、ポートで SSL を有効にします。詳細については、次のトピックを参照してください。 HTTP トランスポート セキュリティ.

  4. WSHttpBinding を使用している場合、セキュリティで保護されたセッションを確立する必要がないときは、EstablishSecurityContext プロパティを false に設定します。

    セキュリティで保護されたセッションは、クライアントとサーバーが対称キーを使用してチャネルを作成するときに発生します (メッセージ交換中、やりとりが終了するまで、クライアントとサーバーの両方が同じキーを使用します)。

クライアント資格情報の種類の設定

適切なクライアント資格情報の種類を選択します。詳細については、次のトピックを参照してください。 資格情報の種類の選択.使用できるクライアント資格情報の種類は、次のとおりです。

  • Windows

  • Certificate

  • Digest

  • Basic

  • UserName

  • NTLM

  • IssuedToken

モードの設定に応じて、資格情報の種類を設定する必要があります。たとえば、次の構成例に示すように、wsHttpBinding を選択しており、モードを "Message" に設定した場合は、Message 要素の clientCredentialType 属性の値を NoneWindowsUserNameCertificate、および IssuedToken のいずれかに設定できます。

<system.serviceModel>
<bindings>
  <wsHttpBinding>
    <binding name="myBinding">
      <security mode="Message"/>
      <message clientCredentialType="Windows"/>
    </binding>
</bindings>
</system.serviceModel>

または

Dim b As New WSHttpBinding()
b.Name = "myBinding"
b.Security.Mode = SecurityMode.Message
b.Security.Message.ClientCredentialType = MessageCredentialType.Windows
WSHttpBinding b = new WSHttpBinding();
b.Name = "myBinding";
b.Security.Mode = SecurityMode.Message;
b.Security.Message.ClientCredentialType=MessageCredentialType.Windows;

サービス資格情報の値の設定

クライアント資格情報の種類を選択したら、サービスとクライアントが使用する実際の資格情報を設定する必要があります。サービスでは、資格情報は ServiceCredentials クラスを使用して設定します。また、資格情報は ServiceHostBase クラスの Credentials プロパティによって返されます。使用しているバインディングによって、サービス資格情報の種類、選択されるセキュリティ モード、およびクライアント資格情報の種類が暗黙的に決まります。サービス資格情報の証明書を設定するコードを次に示します。

' 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 commmunication error occurred: {0}", ce.Message)
    Console.WriteLine()
Catch exc As System.Exception
    Console.WriteLine("An unforseen error occurred: {0}", exc.Message)
    Console.ReadLine()
End Try
// 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 commmunication error occurred: {0}", ce.Message);
    Console.WriteLine();
}
catch (System.Exception exc)
{
    Console.WriteLine("An unforseen error occurred: {0}", exc.Message);
    Console.ReadLine();
}

クライアント資格情報の値の設定

クライアントでは、クライアント資格情報の値は ClientCredentials クラスを使用して設定します。また、クライアント資格情報の値は ClientBase クラスの ClientCredentials プロパティから返されます。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.
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()
// 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();

参照

その他のリソース

基本的な WCF プログラミング
一般的なセキュリティ シナリオ