次の方法で共有


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

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

特に WCF に関するセキュリティの概念の貴重な概要については、MSDN の一連のパターンとプラクティスに関するチュートリアルを Web サービス拡張機能 (WSE) 3.0 のシナリオ、パターン、実装ガイダンスで参照してください。

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

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

WCF のセキュリティ モードを使用したプログラミングの一般的な手順を次に示します。

  1. アプリケーションの要件に適した定義済みのバインドのいずれかを選択します。 バインドの選択肢一覧については、「System-Provided バインディング」をご覧ください。 既定では、ほぼすべてのバインディングでセキュリティが有効になっています。 唯一の例外は、BasicHttpBinding クラスです(構成設定を使用し、<basicHttpBinding>を指します)。

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

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

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

    1. Transport

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

    2. Message

      メッセージ セキュリティとは、すべてのメッセージに、メッセージをセキュリティで保護するために必要なヘッダーとデータが含まれていることを意味します。 ヘッダーの構成は異なるため、任意の数の資格情報を含めることができます。 これは、トランスポート メカニズムで提供できない特定の資格情報の種類を要求する他のサービスと相互運用する場合、またはメッセージを複数のサービスで使用する必要がある場合に、各サービスが異なる資格情報の種類を要求する場合の要因になります。

      詳細については、「 メッセージ セキュリティ」を参照してください。

    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 属性を、 NoneWindowsUserNameCertificateIssuedTokenのいずれかの値に設定することもできます。

<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: {ce.Message}");
    Console.WriteLine();
}
catch (System.Exception exc)
{
    Console.WriteLine($"An unforeseen error occurred: {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 @ {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()

こちらも参照ください