次の方法で共有


WCF での委任と偽装

偽装 は、サービス がサービス ドメインのリソースへのクライアント アクセスを制限するために使用する一般的な手法です。 サービス ドメイン リソースには、ローカル ファイル (偽装) などのマシン リソース、またはファイル共有 (委任) などの別のコンピューター上のリソースを指定できます。 サンプル アプリケーションについては、「クライアントの 偽装」を参照してください。 偽装を使用する方法の例については、「 方法: サービスでクライアントを偽装する」を参照してください。

Von Bedeutung

サービスでクライアントを偽装する場合、サービスはクライアントの資格情報を使用して実行され、サーバー プロセスよりも高い特権を持つ可能性があることに注意してください。

概要

通常、クライアントはサービスを呼び出して、クライアントに代わってサービスに何らかのアクションを実行させます。 偽装を使用すると、アクションの実行中にサービスをクライアントとして機能できます。 委任を使用すると、バックエンド サービスがクライアントを偽装できるように、フロントエンド サービスはクライアントの要求をバックエンド サービスに転送できます。 偽装は、クライアントが特定のアクションの実行を承認されているかどうかを確認する方法として最も一般的に使用されますが、委任は、偽装機能とクライアントの ID をバックエンド サービスに流す方法です。 委任は、Kerberos ベースの認証を実行するときに使用できる Windows ドメイン機能です。 委任は ID フローとは異なり、委任はクライアントのパスワードを所有せずにクライアントを偽装する機能を転送するため、ID フローよりもはるかに高い特権操作です。

偽装と委任の両方で、クライアントに Windows ID が必要です。 クライアントが Windows ID を持っていない場合、使用できる唯一のオプションは、クライアントの ID を 2 つ目のサービスにフローすることです。

偽装の基本

Windows Communication Foundation (WCF) では、さまざまなクライアント資格情報の偽装がサポートされています。 このトピックでは、サービス メソッドの実装中に呼び出し元を偽装するためのサービス モデルのサポートについて説明します。 これらのシナリオでは、偽装と SOAP セキュリティと WCF オプションを含む一般的な展開シナリオについても説明します。

このトピックでは、SOAP セキュリティを使用する場合の WCF での偽装と委任について説明します。 「トランスポート セキュリティでの偽装の使用」の説明に従って、トランスポート セキュリティを使用する場合は、WCF で 偽装と委任を使用することもできます。

2 つのメソッド

WCF SOAP セキュリティには、偽装を実行するための 2 つの異なる方法があります。 使用されるメソッドは、バインディングによって異なります。 1 つは、セキュリティ サポート プロバイダー インターフェイス (SSPI) または Kerberos 認証から取得した Windows トークンからの偽装であり、サービスにキャッシュされます。 2 つ目は、Kerberos 拡張機能から取得した Windows トークンの偽装です。総称 して Service-for-User (S4U) と呼ばれます。

キャッシュされたトークンの偽装

キャッシュ トークンの偽装は、次の方法で実行できます。

  • WSHttpBindingWSDualHttpBinding、Windows クライアント資格情報を使用した NetTcpBinding

  • BasicHttpBinding BasicHttpSecurityModeTransportWithMessageCredential資格情報に設定するか、サービスが有効な Windows アカウントにマップできるユーザー名の資格情報をクライアントが提示するその他の標準バインディングを使用します。

  • requireCancellationtrue に設定された Windows クライアント資格情報を使用するCustomBinding。 (プロパティは、 SecureConversationSecurityTokenParametersSslSecurityTokenParametersSspiSecurityTokenParametersの各クラスで使用できます)。バインディングでセキュリティで保護された会話を使用する場合は、 requireCancellation プロパティも true に設定されている必要があります。

  • クライアントがユーザー名の資格情報を提示する任意の CustomBinding 。 バインディングでセキュリティで保護された会話を使用する場合は、 requireCancellation プロパティも true に設定されている必要があります。

S4U-Based 偽装

S4U ベースの偽装は、次の方法で実行できます。

  • WSHttpBindingWSDualHttpBinding、およびサービスが有効な Windows アカウントにマップできる証明書クライアント資格情報を使用して NetTcpBinding します。

  • requireCancellation プロパティが false に設定された Windows クライアント資格情報を使用するCustomBinding

  • ユーザー名または Windows クライアント資格情報を使用し、falseに設定された requireCancellation プロパティとの安全な会話を使用するCustomBinding

サービスがクライアントを偽装できる範囲は、サービス アカウントが偽装を試みたときに保持する特権、使用される偽装の種類、および場合によってはクライアントが許可する偽装の範囲によって異なります。

クライアントとサービスが同じコンピューター上で実行されていて、クライアントがシステム アカウント ( Local SystemNetwork Serviceなど) で実行されている場合、ステートフル セキュリティ コンテキスト トークンを使用してセキュリティで保護されたセッションが確立されたときに、クライアントを偽装することはできません。 Windows フォームまたはコンソール アプリケーションは、通常、現在ログインしているアカウントで実行されるため、アカウントは既定で偽装できます。 ただし、クライアントが ASP.NET ページであり、そのページが IIS 6.0 または IIS 7.0 でホストされている場合、クライアントは既定で Network Service アカウントで実行されます。 セキュリティで保護されたセッションをサポートするすべてのシステム提供のバインドでは、既定でステートレス セキュリティ コンテキスト トークン (SCT) が使用されます。 ただし、クライアントが ASP.NET ページであり、ステートフルな SCT を持つセキュリティで保護されたセッションが使用されている場合、クライアントを偽装することはできません。 セキュリティで保護されたセッションでステートフルな SCT を使用する方法の詳細については、「 方法: セキュリティで保護されたセッションのセキュリティ コンテキスト トークンを作成する」を参照してください。

サービス メソッドでの偽装: 宣言型モデル

ほとんどの偽装シナリオでは、呼び出し元コンテキストでサービス メソッドを実行する必要があります。 WCF には、ユーザーが OperationBehaviorAttribute 属性で偽装要件を指定できるようにすることで、これを簡単に実行できる偽装機能が用意されています。 たとえば、次のコードでは、WCF インフラストラクチャは、 Hello メソッドを実行する前に呼び出し元を偽装します。 Hello メソッド内のネイティブ リソースへのアクセスは、リソースのアクセス制御リスト (ACL) で呼び出し元のアクセス権限が許可されている場合にのみ成功します。 偽装を有効にするには、次の例に示すように、Impersonation プロパティをImpersonationOption.RequiredまたはImpersonationOption.AllowedのいずれかのImpersonationOption列挙値に設定します。

サービスの資格情報がリモート クライアントよりも高い場合、 Impersonation プロパティが Allowed に設定されている場合、サービスの資格情報が使用されます。 つまり、低い特権を持つユーザーが資格情報を提供した場合、高い特権を持つサービスはサービスの資格情報を使用してメソッドを実行し、低い特権を持つユーザーが使用できないリソースを使用できます。

[ServiceContract]
public interface IHelloContract
{
    [OperationContract]
    string Hello(string message);
}

public class HelloService : IHelloService
{
    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public string Hello(string message)
    {
        return "hello";
    }
}

<ServiceContract()> _
Public Interface IHelloContract
    <OperationContract()> _
    Function Hello(ByVal message As String) As String
End Interface


Public Class HelloService
    Implements IHelloService

    <OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
    Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
        Return "hello"
    End Function
End Class

WCF インフラストラクチャは、Windows ユーザー アカウントにマップできる資格情報を使用して呼び出し元が認証されている場合にのみ、呼び出し元を偽装できます。 Windows アカウントにマップできない資格情報を使用して認証するようにサービスが構成されている場合、サービス メソッドは実行されません。

Windows XP では、ステートフル SCT が作成されると偽装が失敗し、 InvalidOperationExceptionが発生します。 詳細については、「 サポートされていないシナリオ」を参照してください。

サービス メソッドでの偽装: 命令型モデル

場合によっては、呼び出し元がサービス メソッド全体を偽装して機能させる必要はなく、その一部に対してのみ呼び出し元が偽装する必要があります。 この場合は、サービス メソッド内で呼び出し元の Windows ID を取得し、偽装を強制的に実行します。 これを行うには、ServiceSecurityContextWindowsIdentity プロパティを使用して、WindowsIdentity クラスのインスタンスを返し、インスタンスを使用する前に Impersonate メソッドを呼び出します。

偽装アクションを自動的に元に戻すには、必ず Visual BasicUsing ステートメントまたは C# using ステートメントを使用してください。 ステートメントを使用しない場合、または Visual Basic または C# 以外のプログラミング言語を使用する場合は、偽装レベルを元に戻してください。 これを行わないと、サービス拒否攻撃と特権昇格攻撃の基礎が形成される可能性があります。

public class HelloService : IHelloService
{
    [OperationBehavior]
    public string Hello(string message)
    {
        WindowsIdentity callerWindowsIdentity =
        ServiceSecurityContext.Current.WindowsIdentity;
        if (callerWindowsIdentity == null)
        {
            throw new InvalidOperationException
           ("The caller cannot be mapped to a WindowsIdentity");
        }
        using (callerWindowsIdentity.Impersonate())
        {
            // Access a file as the caller.
        }
        return "Hello";
    }
}
Public Class HelloService
    Implements IHelloService

    <OperationBehavior()> _
    Public Function Hello(ByVal message As String) As String _
       Implements IHelloService.Hello
        Dim callerWindowsIdentity As WindowsIdentity = _
            ServiceSecurityContext.Current.WindowsIdentity
        If (callerWindowsIdentity Is Nothing) Then
            Throw New InvalidOperationException( _
              "The caller cannot be mapped to a WindowsIdentity")
        End If
        Dim cxt As WindowsImpersonationContext = callerWindowsIdentity.Impersonate()
        Using (cxt)
            ' Access a file as the caller.
        End Using

        Return "Hello"

    End Function
End Class

すべてのサービス メソッドの偽装

場合によっては、呼び出し元のコンテキストでサービスのすべてのメソッドを実行する必要があります。 メソッドごとにこの機能を明示的に有効にする代わりに、 ServiceAuthorizationBehaviorを使用します。 次のコードに示すように、 ImpersonateCallerForAllOperations プロパティを true に設定します。 ServiceAuthorizationBehaviorは、ServiceHost クラスの動作のコレクションから取得されます。 また、各メソッドに適用されるOperationBehaviorAttributeImpersonation プロパティも、AllowedまたはRequiredに設定する必要があることに注意してください。

// Code to create a ServiceHost not shown.
ServiceAuthorizationBehavior MyServiceAuthorizationBehavior =
    serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = true;
' Code to create a ServiceHost not shown.
Dim MyServiceAuthorizationBehavior As ServiceAuthorizationBehavior
MyServiceAuthorizationBehavior = serviceHost.Description.Behaviors.Find _
(Of ServiceAuthorizationBehavior)()
MyServiceAuthorizationBehavior.ImpersonateCallerForAllOperations = True

次の表では、 ImpersonationOptionImpersonateCallerForAllServiceOperationsのすべての可能な組み合わせに対する WCF 動作について説明します。

ImpersonationOption ImpersonateCallerForAllServiceOperations 行動
必須 n/a WCF が呼び出し元を偽装する
許可 偽り WCF が呼び出し元を偽装しない
許可 ほんとう WCF が呼び出し元を偽装する
許可されていません 偽り WCF が呼び出し元を偽装しない
許可されていません ほんとう 禁止。 ( InvalidOperationException がスローされます)。

Windows 資格情報とキャッシュ されたトークンの偽装から取得された偽装レベル

一部のシナリオでは、Windows クライアント資格情報を使用するときにサービスが実行する偽装のレベルをクライアントが部分的に制御できます。 1 つのシナリオは、クライアントが匿名偽装レベルを指定するときに発生します。 もう 1 つは、キャッシュされたトークンを使用して偽装を実行するときに発生します。 これを行うには、ジェネリック ChannelFactory<TChannel> クラスのプロパティとしてアクセスされるWindowsClientCredential クラスのAllowedImpersonationLevel プロパティを設定します。

偽装レベルとして Anonymous を指定すると、クライアントは匿名でサービスにログオンします。 そのため、偽装が実行されるかどうかにかかわらず、サービスは匿名ログオンを許可する必要があります。

クライアントは、偽装レベルを AnonymousIdentificationImpersonation、または Delegationとして指定できます。 次のコードに示すように、指定したレベルのトークンのみが生成されます。

ChannelFactory<IEcho> cf = new ChannelFactory<IEcho>("EchoEndpoint");
cf.Credentials.Windows.AllowedImpersonationLevel  =
    System.Security.Principal.TokenImpersonationLevel.Impersonation;
Dim cf As ChannelFactory(Of IEcho) = New ChannelFactory(Of IEcho)("EchoEndpoint")
cf.Credentials.Windows.AllowedImpersonationLevel = _
System.Security.Principal.TokenImpersonationLevel.Impersonation

次の表では、キャッシュされたトークンから偽装するときにサービスが取得する偽装レベルを指定します。

AllowedImpersonationLevel 価値 サービスには次の情報があります。 SeImpersonatePrivilege サービスとクライアントは委任が可能です キャッシュされたトークン ImpersonationLevel
アノニマス イエス n/a ものまね
アノニマス いいえ n/a 識別
識別 n/a n/a 識別
ものまね イエス n/a ものまね
ものまね いいえ n/a 識別
委任 イエス イエス 委任
委任 イエス いいえ ものまね
委任 いいえ n/a 識別

ユーザー名の資格情報とキャッシュされたトークンの偽装から取得された偽装レベル

クライアントは、サービスにユーザー名とパスワードを渡すことによって、WCF がそのユーザーとしてログオンできるようにします。これは、 AllowedImpersonationLevel プロパティを Delegation に設定することと同じです。 ( AllowedImpersonationLevel は、 WindowsClientCredential クラスと HttpDigestClientCredential クラスで使用できます)。次の表は、サービスがユーザー名の資格情報を受け取ったときに取得される偽装レベルを示しています。

AllowedImpersonationLevel サービスには次の情報があります。 SeImpersonatePrivilege サービスとクライアントは委任が可能です キャッシュされたトークン ImpersonationLevel
n/a イエス イエス 委任
n/a イエス いいえ ものまね
n/a いいえ n/a 識別

S4U-Based 偽装から取得した偽装レベル

サービスには次の情報があります。 SeTcbPrivilege サービスには次の情報があります。 SeImpersonatePrivilege サービスとクライアントは委任が可能です キャッシュされたトークン ImpersonationLevel
イエス イエス n/a ものまね
イエス いいえ n/a 識別
いいえ n/a n/a 識別

Windows アカウントへのクライアント証明書のマッピング

クライアントは、証明書を使用してサービスに対して自身を認証し、Active Directory を介してクライアントを既存のアカウントにマップすることができます。 次の XML は、証明書をマップするようにサービスを構成する方法を示しています。

<behaviors>  
  <serviceBehaviors>  
    <behavior name="MapToWindowsAccount">  
      <serviceCredentials>  
        <clientCertificate>  
          <authentication mapClientCertificateToWindowsAccount="true" />  
        </clientCertificate>  
      </serviceCredentials>  
    </behavior>  
  </serviceBehaviors>  
</behaviors>  

次のコードは、サービスを構成する方法を示しています。

// Create a binding that sets a certificate as the client credential type.  
WSHttpBinding b = new WSHttpBinding();  
b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;  
  
// Create a service host that maps the certificate to a Windows account.  
Uri httpUri = new Uri("http://localhost/Calculator");  
ServiceHost sh = new ServiceHost(typeof(HelloService), httpUri);  
sh.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;  

委任

バックエンド サービスに委任するには、サービスで Kerberos マルチレッグ (NTLM フォールバックなしの SSPI) または Kerberos によるクライアントの Windows ID を使用したバックエンド サービスへの直接認証を実行する必要があります。 バックエンド サービスに委任するには、 ChannelFactory<TChannel> とチャネルを作成し、クライアントを偽装しながらチャネルを介して通信します。 この形式の委任では、フロントエンド サービスからバックエンド サービスを配置できる距離は、フロントエンド サービスによって実現される偽装レベルによって異なります。 偽装レベルが Impersonationされている場合は、フロントエンド サービスとバックエンド サービスが同じコンピューター上で実行されている必要があります。 偽装レベルが Delegationされている場合、フロントエンド サービスとバックエンド サービスは、別のコンピューターまたは同じコンピューター上に配置できます。 委任レベルの偽装を有効にするには、委任を許可するように Windows ドメイン ポリシーを構成する必要があります。 委任のサポートのために Active Directory を構成する方法の詳細については、「 委任された認証の有効化」を参照してください。

クライアントがバックエンド サービスの Windows アカウントに対応するユーザー名とパスワードを使用してフロントエンド サービスに対して認証を行う場合、フロントエンド サービスは、クライアントのユーザー名とパスワードを再利用してバックエンド サービスに対して認証を行うことができます。 バックエンド サービスにユーザー名とパスワードを渡すと、バックエンド サービスが偽装を実行できるため、これは特に強力な形式の ID フローですが、Kerberos が使用されていないため委任は構成されません。 委任に対する Active Directory コントロールは、ユーザー名とパスワードの認証には適用されません。

偽装レベルの関数としての委任機能

偽装レベル サービスはプロセス間の委任を実行できます サービスはマシン間の委任を実行できます
Identification いいえ いいえ
Impersonation イエス いいえ
Delegation イエス イエス

次のコード例は、委任の使用方法を示しています。

public class HelloService : IHelloService
{
    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public string Hello(string message)
    {
        WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
        if (callerWindowsIdentity == null)
        {
            throw new InvalidOperationException
             ("The caller cannot be mapped to a Windows identity.");
        }
        using (callerWindowsIdentity.Impersonate())
        {
            EndpointAddress backendServiceAddress = new EndpointAddress("http://localhost:8000/ChannelApp");
            // Any binding that performs Windows authentication of the client can be used.
            ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(new NetTcpBinding(), backendServiceAddress);
            IHelloService channel = channelFactory.CreateChannel();
            return channel.Hello(message);
        }
    }
}
Public Class HelloService
    Implements IHelloService

    <OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
    Public Function Hello(ByVal message As String) As String Implements IHelloService.Hello
        Dim callerWindowsIdentity As WindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity
        If (callerWindowsIdentity Is Nothing) Then
            Throw New InvalidOperationException("The caller cannot be mapped to a Windows identity.")
        End If

        Dim backendServiceAddress As EndpointAddress = New EndpointAddress("http://localhost:8000/ChannelApp")
        ' Any binding that performs Windows authentication of the client can be used.
        Dim channelFactory As ChannelFactory(Of IHelloService) = _
          New ChannelFactory(Of IHelloService)(New NetTcpBinding(), backendServiceAddress)
        Dim channel As IHelloService = channelFactory.CreateChannel()
        Return channel.Hello(message)
    End Function
End Class

制約付き委任を使用するようにアプリケーションを構成する方法

制約付き委任を使用する前に、送信側、受信側、およびドメイン コントローラーを構成する必要があります。 次の手順では、制約付き委任を有効にする手順を示します。 委任と制約付き委任の違いの詳細については、制約付きディスカッションについて説明する Windows Server 2003 Kerberos 拡張機能 の部分を参照してください。

  1. ドメイン コントローラーで、[ アカウントは機密性が高 く、クライアント アプリケーションが実行されているアカウントに委任できません] チェック ボックスをオフにします。

  2. ドメイン コントローラーで、クライアント アプリケーションが実行されているアカウントの [委任に対して 信頼されている アカウント] チェック ボックスをオンにします。

  3. ドメイン コントローラーで、[委任用のコンピューターを信頼する] オプションをクリックして、委任に対して信頼されるように中間層 コンピューター を構成します。

  4. ドメイン コントローラーで、制限付き委任を使用するように中間層コンピューターを構成します。そのためには、[ このコンピューターを指定されたサービスのみに委任する] オプションを クリックします。

制約付き委任の構成の詳細な手順については、「 Kerberos プロトコルの移行」と「制約付き委任」を参照してください。

こちらも参照ください