Tuesday, 15 November 2011

Basics of WCF Security – Part 3

Series : Part-1  Part-2  Part-3
In last edition of Basics of WCF Security series, we discussed ProtectionLevel Security Setting in WCF. Today’s WCF corner is a continuation on the same topic. As usual, this article assumes that you have a fair understanding of basics of WCF and you have at least written or seen a simple WCF application in action.
In this article we will cover Impersonation/Delegation:
Impersonation is a common technique that services use to restrict client access to a service domain's resources. Service domain resources can either be machine resources, such as local files (impersonation), or a resource on another machine, such as a file share (delegation). In short, WCF services use Impersonation to assume the original caller’s identity in order to authorize access to service resources (such as files or database tables)
By default, impersonation is disabled and resources are accessed by using the WCF service’s process identity. You can enable impersonation either programmatically or by applying appropriate attributes at operation or service levels.
Impersonation can be done imperatively or declaratively. 
1.       Imperative impersonation is performed programmatically at run time and can vary depending on business logic or other conditions. 
2.       Declarative impersonation is applied with a static attribute that can be associated with an operation or an entire interface.
 In general, you should use imperative impersonation when you need the fine granularity made possible by writing the impersonation logic into your code. If you do not need such fine granularity, you can use declarative impersonation. 
Delegation allows you to use an impersonation token to access network resources. Your ability to use delegation depends on the authentication mechanism in use and appropriate account configuration.

Impersonation Methods

There are three methods used for impersonation: 

  • Impersonate the Original Caller Declaratively on Specific Operations

You can impersonate declaratively on an operation when you want to impersonate the original caller for the entire duration of a specific operation. Use impersonation selectively and only on the operations that need it, since by nature it increases the potential attack surface of your application. 
You can impersonate declaratively by applying the OperationBehavior attribute on any operation that requires client impersonation. The following example shows how to impersonate for a specific operation. 
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetData(int value)
{
   return “test”;
}
  • Impersonate the Original Caller Declaratively for the Entire Service

Impersonate declaratively on a service when you want to impersonate the original caller for all of the operations in your service. However, you should be careful with this option because it can significantly increase the attack surface of your application by running all of your code under a higher-privileged account. 
You can impersonate the entire service by applying the impersonateCallerForAllOperations attribute to "true" in the WCF configuration file. The following example shows how to impersonate for entire service: 
...
<behaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <serviceAuthorization impersonateCallerForAllOperations="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>
...

If you are impersonating all operations in the service, the Impersonation property of the OperationBehaviorAttribute applied to each operation will be overriden. Therefore if the property on the operation is set to something other than Allowed or Required, impersonation will be turned off for that operation.
Note: When a service has higher credentials than the remote client, the credentials of the service are used if the Impersonation property is set to Allowed. That is, if a low-privileged user provides its credentials, a higher-privileged service executes the method with the credentials of the service, and can use resources that the low-privileged user would otherwise not be able to use.
 
  • Impersonate the Original Caller Programmatically Within an Operation

Impersonate programmatically when you want to impersonate the original caller for a short duration in a service operation. You can impersonate programmatically by calling the Impersonate() method on the Windows identity that you want to impersonate, as follows:

public string GetData(int value)
{       
 using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
 {
  // return the impersonated user (original users identity)
  return string.Format("Hi, {0}, you have entered: {1}",
  WindowsIdentity.GetCurrent().Name, value);
 }   
}

Note: It is important to revert to impersonation. Failure to do so can form the basis for denial of service (DoS) or elevation of privilege attacks. In the example above, the using statement ensures that the impersonation is reverted after execution of the using block.

Controlling Impersonation on the Service Side

You can control impersonation on the service side by using declarative impersonation. You can use the ImpersonationOption enumeration along with theOperationBehaviorAttribute attribute to control impersonation. The following impersonation options are available:
1.       NotAllowed – Impersonation is not performed in a particular operation.
2.       Allowed – Impersonation is performed if the original Windows token is available and the service is configured to impersonate on all operations using theImpersonateCallerForAllOperations in the ServiceAuthorizationBehavior attribute.
3.       Required – Impersonation is performed; the Windows identity token is required to be available.
The following example uses declarative impersonation to control impersonation on the service side:

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetData(int value)
{
   return “test”;
}

Controlling Impersonation on the Client Side

You can control impersonation on the client side and prevent WCF services from using client identities to access local resources. Windows credentials have an AllowedImpersonationLevel property that is set to one of the following TokenImpersonationLevel options in order to control the impersonation level:
  1. None – The WCF service cannot authenticate or impersonate the user.
  2. Anonymous – The WCF service authenticates clients as anonymous, but cannot obtain information for identification or impersonation.
  3. Identification – The WCF service can authenticate clients and get information for identification, but cannot impersonate the clients. This is the default value.
  4. Impersonation – The WCF service can authenticate, get information for identification, and impersonate clients on local systems.
  5. Delegation – The WCF service can authenticate, get information for identification, and impersonate clients on local as well as remote systems.
The following example shows how to configure the impersonation level on the client side:
<behaviors>
    <endpointBehaviors>
        <behavior name="NewBehavior">
            <clientCredentials>
                <windows allowedImpersonationLevel="Impersonation" />
            </clientCredentials>
        </behavior>
    </endpointBehaviors>
</behaviors>

Note: The impersonation level obtained by the server when it impersonates the client token is not solely a function of this setting. It is also a function of the associated privileges and domain settings for the account in which the service is running.

To conclude:  Clients call a service to have the service perform some action on the client’s behalf and it allows the service to act as the client while performing the action. Both Impersonation and Delegation are powerful tools that one should use very cautiously and selectively. Improper use may result into security vulnerabilities.

Reference:

No comments:

Post a Comment