WCF の委任と偽装

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

ms730088.Important(ja-jp,VS.100).gif 注 :
サービスでクライアントを偽装すると、サービスはそのクライアントの資格情報を使用して実行されます。この資格情報の特権がサーバー プロセスより高い場合があることに注意してください。

概要

通常、クライアントは、クライアントに代わって何らかのアクションを実行してもらうためにサービスを呼び出します。偽装により、サービスはアクションの実行時にクライアントとして機能できます。委任を使用すると、フロントエンド サービスは、バックエンド サービスもクライアントを偽装できるような方法で、バックエンド サービスにクライアントの要求を転送できます。偽装は、クライアントが特定のアクションを実行するために承認されているかどうかを確認する方法として、最も一般的に使用されます。委任は、偽装機能をクライアントの 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 トークンの偽装です。もう 1 つは、Service-for-User (S4U) と総称される Kerberos 拡張から取得した Windows トークンの偽装です。

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

キャッシュされたトークンの偽装は、以下で実行できます。

  • Windows クライアント資格情報を使用する WSHttpBindingWSDualHttpBinding、および NetTcpBinding

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

  • requireCancellationtrue に設定された Windows クライアント資格情報を使用する CustomBinding (このプロパティは、SecureConversationSecurityTokenParametersSslSecurityTokenParameters、および SspiSecurityTokenParameters の各クラスで使用できます)。セキュリティで保護されたメッセージ交換をバインディングで使用する場合は、requireCancellation プロパティを true に設定することも必要です。

  • クライアントがユーザー名資格情報を提示する CustomBinding。セキュリティで保護されたメッセージ交換をバインディングで使用する場合は、requireCancellation プロパティを true に設定することも必要です。

S4U ベースの偽装

S4U ベースの偽装は、以下で実行できます。

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

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

  • requireCancellation プロパティが false に設定されたユーザー名資格情報または Windows クライアント資格情報とセキュリティで保護されたメッセージ交換を使用する CustomBinding

サービスがクライアントを偽装できるエクステントは、偽装を試みるときにサービス アカウントが保持している特権、使用する偽装の種類、およびクライアントが許可すると考えられる偽装のエクステントによって異なります。

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

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

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

ms730088.note(ja-jp,VS.100).gif注 :
サービスの資格情報がリモート クライアントよりも高い場合は、Impersonation プロパティが Allowed に設定されていても、サービスの資格情報が使用されます。つまり、低い特権を持つユーザーがその資格情報を提示した場合、そのユーザーよりも高い特権を持つサービスは、サービスの資格情報を使用してメソッドを実行し、特権の低いユーザーが本来は使用できないリソースを使用できることになります。

<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 
[ServiceContract]
public interface IHelloContract
{
    [OperationContract]
    string Hello(string message);
}

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

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

ms730088.note(ja-jp,VS.100).gif注 :
Windows XP では、ステートフルな SCT が作成されると偽装が失敗し、InvalidOperationException になります。詳細については、次のトピックを参照してください。 サポートされていないシナリオ.

サービス メソッドでの偽装 : 強制モデル

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

ms730088.note(ja-jp,VS.100).gif注 :
Visual Basic の Using ステートメント、または C# の using ステートメントを使用して、偽装操作を自動的に元に戻すようにしてください。これらのステートメントを使用しない場合、または Visual Basic や C# 以外のプログラミング言語を使用する場合は、偽装レベルを必ず元に戻してください。この作業を怠ると、サービス拒否攻撃や権限の昇格攻撃のもとになるおそれがあります。

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 
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";
    }
}

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

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

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

ImpersonationOptionImpersonateCallerForAllServiceOperations の可能なすべての組み合わせに対する WCF の動作を次の表に示します。

ImpersonationOption ImpersonateCallerForAllServiceOperations 動作

Required

n/a

WCF は、呼び出し元を偽装します。

Allowed

false

WCF は、呼び出し元を偽装しません。

Allowed

true

WCF は、呼び出し元を偽装します。

NotAllowed

false

WCF は、呼び出し元を偽装しません。

NotAllowed

true

使用できません (InvalidOperationException がスローされます)。

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

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

ms730088.note(ja-jp,VS.100).gif注 :
匿名偽装レベルを指定すると、クライアントはサービスに匿名でログオンします。したがって、偽装を実行するかどうかに関係なく、サービスは匿名ログオンを許可する必要があります。

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

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

キャッシュされたトークンを使用して偽装するときに、サービスが取得する偽装レベルを次の表に示します。

AllowedImpersonationLevel の値 サービスに SeImpersonatePrivilege がある サービスとクライアントに処理を代行する機能がある キャッシュされたトークンの ImpersonationLevel

Anonymous

はい

適用なし

Impersonation

Anonymous

いいえ

適用なし

Identification

Identification

適用なし

適用なし

Identification

Impersonation

はい

適用なし

Impersonation

Impersonation

いいえ

適用なし

Identification

処理の代行

はい

はい

Delegation

Delegation

はい

いいえ

Impersonation

Delegation

いいえ

適用なし

Identification

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

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

AllowedImpersonationLevel サービスに SeImpersonatePrivilege がある サービスとクライアントは委任する機能がある キャッシュされたトークンの ImpersonationLevel

適用なし

はい

はい

Delegation

適用なし

はい

いいえ

Impersonation

適用なし

いいえ

適用なし

Identification

S4U ベースの偽装から取得する偽装レベル

サービスに SeTcbPrivilege がある サービスに SeImpersonatePrivilege がある サービスとクライアントは委任する機能がある キャッシュされたトークンの ImpersonationLevel

はい

はい

適用なし

Impersonation

はい

いいえ

適用なし

Identification

いいえ

適用なし

適用なし

Identification

クライアント証明書から 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("https://localhost/Calculator");
ServiceHost sh = new ServiceHost(typeof(HelloService), httpUri);
sh.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;

処理の代行

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

ms730088.note(ja-jp,VS.100).gif注 :
バックエンド サービスで Windows アカウントに対応するユーザー名とパスワードを使用して、フロントエンド サービスに対するクライアント認証を行うと、フロントエンド サービスはこのユーザー名とパスワードを再利用して、バックエンド サービスに対する認証を行うことができます。ユーザー名とパスワードをバックエンド サービスに渡すことで、バックエンド サービスが偽装を実行できるため、これは ID フローの特に強力な形式と言えますが、Kerberos を使用しないため、委任は構成されません。Active Directory による委任の制御は、ユーザー名/パスワード認証には適用されません。

偽装レベルの 1 つの機能としての委任機能

偽装レベル サービスがプロセス間の委任を実行できる サービスがコンピューター間の委任を実行できる

Identification

いいえ

いいえ

Impersonation

はい

いいえ

Delegation

はい

はい

委任の使用方法を次のコード例に示します。

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("https://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
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("https://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);
        }
    }
}

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

制約された委任を使用するには、送信側、受信側、およびドメイン コントローラーを制約された委任を使用するように構成する必要があります。制約された委任を有効にする手順を以下に示します。委任と制約された委任の違いの詳細については、「Windows Server 2003 Kerberos 拡張機能」の制約された委任に関する部分を参照してください。

  1. ドメイン コントローラーで、クライアント アプリケーションを実行しているアカウントの [アカウントは重要なので委任できない] チェック ボックスをオフにします。

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

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

  4. ドメイン コントローラーで、[指定されたサービスへの委任でのみこのコンピューターを信頼する] をクリックして、制約された委任を使用するように中間層コンピューターを構成します。

制約された委任を構成する手順の詳細については、MSDN の次のトピックを参照してください。

参照

処理手順

Impersonating the Client
方法 : サービスでクライアントに偽装する

リファレンス

OperationBehaviorAttribute
Impersonation
ImpersonationOption
WindowsIdentity
ServiceSecurityContext
WindowsIdentity
ServiceAuthorizationBehavior
ImpersonateCallerForAllOperations
ServiceHost
AllowedImpersonationLevel
WindowsClientCredential
ChannelFactory
Identification

概念

トランスポート セキュリティでの偽装の使用
ServiceModel メタデータ ユーティリティ ツール (Svcutil.exe)