Adil Akhter's Weblog

August 6, 2009

WCF Security: WCF Performance & ProtectionLevel – Part 2

Filed under: Security, c#, wcf — Tags: , , — adiil @ 8:14 pm

In the last post, I discussed about the problem not being able to configure ProtectionLevel for different endpoint declaratively through configuration. However, it might be a very good requirement for a WCF service and I will show you how. In my today’s post I will go through such a case where I would preferably like to configure ProtectionLevel at runtime through configuration rather imperative way as it is not available in standard Wcf application for bindings like wsHttpBinding and basicHttpBinding & so on.

Why configure ProtectionLevel dynamically thru configuration?

Basically, ProtectionLevel enforce security requirement of request and response messages in the channel and all the stakeholder of the message must conform to the requirement; anything otherwise results in exception. Last post, I showed you, how to configure ProtectionLevel in different level of WCF messaging stack and saw that it can only be set it programmatically in the contract of the service which has impact on all the preconfigured bindings.

Now, let’s say, I want to have 2 different endpoint to use different ProtectionLevel.
In addition, I also want to make it configurable so that I can change the security behavior of the endpoint conveniently after it has been deployed.

Why would I want that? Good question. Consider following case when I have only one endpoint and I am using message level security with wsHttpBinding (or ws2007httpbinding preferable one for internet based Wcf Service). For internet users consuming this service, I am using ProtectionLevel.EncryptAndSign because of security requirement of our application.

However, in case of our intranet, I don’t want to take the overhead of
ProtectionLevel.EncryptAndSign rather would like to use ProtectionLevel.Sign to make the service a bit more responsive and efficient by getting rid of the overhead of encryption of request and response. And most importantly, I don’t need ProtectionLevel.EncryptAndSign for the messages in users in Intranet as per security requirement. Out of the box, there is no features available that will enable to use different ProtectionLevel in these 2 cases. Duh! Obviously there is one option to host to service twice by compiling the code in 2 different ProtectionLevel. At 1 to 10 scale, how would you rate this solution ? J Ok , then let’s move on…


So, what we need is – make the 2 different endpoints to work with different ProtectionLevel and using custom endpoint behavior , it can be easily done. In that case, internet users will use the wsHttpBinding with default ProtectionLevel and the intranet user will use less secure


ProtectionLevel.Sign. In the next section, I will explain step by step how to do it.

How to configure ProtectionLevel dynamically thru configuration?

I hope, by this time it is clear , why we need it to configure it dynamically. If you have question, please let me know.

  1. First create a Custom EndpointBehavior by implementing IEndpointBehavior as below –

    public class MessageSecurityBehavior:IEndpointBehavior
    {
    public ProtectionLevel ProtectionLevel { get; set; }

    #region IEndpointBehavior Members

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
    //Do nothing
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
    //Do nothing
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    //Do nothing
    }

    public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection parameters)
    {
    //Setting the ProtectionLevel at the Service Contract
    serviceEndpoint.Contract.ProtectionLevel = ProtectionLevel;

    parameters.Remove();

    ChannelProtectionRequirements requirements = new ChannelProtectionRequirements();
    parameters.Add(requirements);

    MessagePartSpecification unprotectedBody = new MessagePartSpecification();
    MessagePartSpecification protectedBody = new MessagePartSpecification(true);

    switch (ProtectionLevel)
    {
    case ProtectionLevel.None:
    requirements.OutgoingSignatureParts.AddParts(unprotectedBody, “*”);
    requirements.IncomingSignatureParts.AddParts(unprotectedBody, “*”);
    requirements.OutgoingEncryptionParts.AddParts(unprotectedBody, “*”);
    requirements.IncomingEncryptionParts.AddParts(unprotectedBody, “*”);
    break;
    case ProtectionLevel.Sign:
    requirements.OutgoingSignatureParts.AddParts(protectedBody, “*”);
    requirements.IncomingSignatureParts.AddParts(protectedBody, “*”);

    requirements.OutgoingEncryptionParts.AddParts(unprotectedBody, “*”);
    requirements.IncomingEncryptionParts.AddParts(unprotectedBody, “*”);
    break;
    case ProtectionLevel.EncryptAndSign:
    requirements.OutgoingSignatureParts.AddParts(protectedBody, “*”);
    requirements.IncomingSignatureParts.AddParts(protectedBody, “*”);
    requirements.OutgoingEncryptionParts.AddParts(protectedBody, “*”);
    requirements.IncomingEncryptionParts.AddParts(protectedBody, “*”);
    break;
    }
    }

    #endregion
    }

    Listing 1

  2. Create a BehaviorElement by extending BehaviorExtensionElement to make the behavior configurable through config file.

    ///


    /// Represents Element to set the ProtectionLevel to different Endpoint using configuration
    ///

    public class MessageSecurityBehaviorElement : BehaviorExtensionElement
    {
    private const string PROTECTION_LEVEL_ELEMENT_NAME = “messageProtection”;
    public override Type BehaviorType
    {
    get
    {
    return typeof(MessageSecurityBehavior);
    }
    }

    protected override object CreateBehavior()
    {
    return new MessageSecurityBehavior { ProtectionLevel = this.ProtectionLevel };
    }

    [ConfigurationProperty(PROTECTION_LEVEL_ELEMENT_NAME)]
    public ProtectionLevel ProtectionLevel
    {

    get
    {
    return (ProtectionLevel)base[PROTECTION_LEVEL_ELEMENT_NAME];
    }

    set
    {
    base[PROTECTION_LEVEL_ELEMENT_NAME] = value;
    }

    }

    private ConfigurationPropertyCollection properties = null;
    protected override ConfigurationPropertyCollection Properties
    {
    get
    {
    if (this.properties == null)
    {

    ConfigurationPropertyCollection propertys = new ConfigurationPropertyCollection();
    propertys.Add(new ConfigurationProperty(PROTECTION_LEVEL_ELEMENT_NAME, typeof(ProtectionLevel), null, ConfigurationPropertyOptions.IsRequired));
    properties = propertys;
    }
    return properties;
    }

    }

    }

    Listing 2

  3. So, seems like coding part is done. Let’s start configuring it. To do so, first thing that needs to be done is to add a behaviorExtensions inside system.serviceModel > behaviorExtensions specifying the newly created custom Endpoint behavior :
    <system.serviceModel>
    
        <extensions>
          <behaviorExtensions>
            <add name="messageProtection" type="TestService. MessageSecurityBehaviorElement, TestService"/>
          </behaviorExtensions>
        </extensions>
    	<!--Rest of the configuration-->
    </system.serviceModel>
    

    Listing 3

  4. Then, create a endpoint behavior like below :
    <system.serviceModel>
    <behaviors>
    <endpointBehaviors>
            <behavior name="noneProtectionLevelForEndPoint">
          		    <messageProtection protectionLevel="None"/>
            </behavior>
          	</endpointBehaviors>
     </behaviors>
    <!--Rest of the configuration-->
    </system.serviceModel>
     

    Listing 4

  5. Now, if I need to use this kind of ProtectionLevel that I configured at step 4 in any endpoint , I just need to add it as behaviorConfiguration. and I am done.
    <system.serviceModel>
    
    <!-- Rest of the configuration-->
    <endpoint address="wsHttp"
                      binding="wsHttpBinding"
                      name="wsBinding.ModeMessage.CredentialNone.BindingName"
    contract="TestService.ITestService"
                      behaviorConfiguration="noneProtectionLevelForEndPoint">
              <identity>
                <dns value="localhost"/>
              </identity>
            </endpoint>
    </system.serviceModel>
    

    Listing 5

A bit details about the MessageSecurityBehavior:

So, now since I just showed you how to configure ProtectionLevel at runtime , let’s go for bit more explanation of MessageSecurityBehavior ; only if you are interested. By changing the ChannelProtectionRequirement of the Endpoint, the new custom behavior impacts the request and response in the channel. Moreover , the contract also binds to the configured ProtectionLevel.

Then 2 different MessagePartSpecification was created where first 1st one is a empty MessagePartSpecification and 2nd one refers to the MessagePartSpecification which contains body.


Then, depending of different value ProtectionLevel, the MessagePartSpecification are set to the ChannelProtectionRequirements.

For example, in case ProtectionLevel.Sign , in OutgoingSignatureParts and IncomingSignatureParts of ChannelProtectionRequirements, MessagePartSpecification that included Body is being added to be signed from client to the server and again back to client from server. However, in this case , encryption is not needed , so in OutgoingEncryptionParts and IncomingEncryptionParts, empty MessagePartSpecification is added and that results in unencrypted messages.

Conclusion

It’s not difficult to update the ProtectionLevel
at runtime, but bear in mind that client and server always have to conform to the
ProtectionLevel
requirement, which means, updating the
ProtectionLevel
requirement at runtime might results in updating the clients configuration/code. It’s a great tool, use it with care
J. Any pops up, just give me a buzz.

Additional Links

  1. WCF Security: WCF Performance & ProtectionLevel – Part 1 : http://adilakhter.wordpress.com/2009/08/06/wcf-security-wcf-performance-protectionlevel-part-1/
  2. Custom WCF Behaviors through App.Config :http://winterdom.com/2006/10/customwcfbehaviorsthroughappconfig
  3. Configuring ProtectionLevel : http://blogs.msdn.com/drnick/archive/2008/03/10/configuring-protection-level.aspx
  4. Fundamentals of WCF Security : http://www.code-magazine.com/article.aspx?quickid=0611051

WCF Security: WCF Performance & ProtectionLevel – Part 1

Filed under: Security, wcf — adiil @ 8:08 pm

After digging a bit further in WCF performance , it become really clear difference that if we want to increase performance of our WCF service hosted for internet, and we are supporting digital signature , and our data is not that sensitive , we can go for ProtectionLevel.None for the WsHttpBinding. Here is one comparison done for our Wcf Service shows that using ProtectionLevel.None, wsHttpBinding is performing pretty impressive :


Result is quite obvious also as encrypt and sign operation definitely take some time in every request and response.

A bit More about ProtectionLevel :

Using ProtectionLevel attribute , we can do following –

  • We can require a binding to use certain minimum level of Protection, where the value of ProtectionLevel can be None , Sign and EncryptAndSign.
  • We can throttle message protection.
  • By default , when security is turned on, value of the ProtectionLevel is EncryptAndSign.

Hence, the way I personally see ProtectionLevel as a requirement that we can set to the service so that consumer of the service has to comply with that particular requirement. By saying that what I mean is – in the service side we can set the ProtectionLevel = ProtectionLevel.None , meaning consumer of the service can use anything above it such as ProtectionLevel.Sign or ProtectionLevel.EncryptAndSign.

How can we configure it ? :

If we are using transport binding like – nettcpBinding, we can change ProtectionLevel using the <binding> configuration –

<netTcpBinding>
        <binding name="SignOnlyProectionLevelBindingConfiguration">
          <security mode ="Transport" >
<transport protectionLevel="Sign"/>
          </security>
        </binding>
</netTcpBinding>

Listing : 1

However, we cannot configure ProtectionLevel by configuration in case of some binding such as – wsHttpBinding or basicHttpBinding. Only way to configure it is through programmatically:

[ServiceContract(Namespace="http://www.testservice.protectionlevel.net" ,
ProtectionLevel = ProtectionLevel.Sign)
]
public interface ITestService
{
}

Listing : 2

So, we cannot change the ProtectionLevel of these bindings with message level security thru configuration after it has been deployed. Worst of it , we can not specify different ProtectionLevel for different bindings as we need to specify it at the Contract Level in the code L. However, there is way to do it that I am going to discuss it in my next post.

We can also set the ProtectionLevel in different levels of WCF Message by specifying it in the following attributes :


And specifying a ProtectionLevel at the top level will have impact in all the levels below unless it is overridden. For example , we can specify ProtectionLevel like below –

[ServiceContract(Namespace="http://www.testservice.protectionlevel.net" ,
ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public interface ITestService
{
[OperationContract(ProtectionLevel= ProtectionLevel.None)]
string GetSessionId();

[OperationContract]
string GetSessionIdEncrypted();

}

Listing : 3

Even if at the ServiceContract , ProtectionLevel requirement is EncryptAndSign , we override it in GetSessionId by setting the ProtectionLevel requirement to None, meaning , the ProtectionLevel in the lower levels such as MessageContract , MessageHeader and MessageBody will conform to the ProtectionLevel.None for GetSessionId as we can see the request and response as plain text.

On the other hand , GetSessionIdEncrypted will have encrypted and signed message in the wire as set at the OperationContract–


And by setting different ProtectionLevel in different level , we can make our service more efficient and responsive. Lets say , by default our service does not require any encryption and signing at the service contract level, however , service might impose ProtectionLevel.Sign or ProtectionLevel.EncryptAndSign to some sensitive operation contract to impose message protection requirement to the client. Seems like a very handy feature J.


Please bear in mind, ProtectionLevel relies on WS-Addressing to support this kind of different level of ProtectionLevel in different Level. So , it will result in an unexpected behavior if it is used in Binding what does not support WS-Addressing spec. for example : BasicHttpBinding.

In addition, choosing a value for ProctectionLevel does not have any impact in case transport level security as by default it is dependent on Transport Layer Security. For example, in a pretty general case, let’s say , we are running our WCF application over HTTP SSL , it does not matter which ProtectionLevel we are using as by default it will encrypt & sign at the transport layer.

Conclusion

ProtectionLevel is quite a powerful attribute. Hence , use it with care. Please feel free to ask if anything pops up. Will be waiting for your feedback. Chao!

WCF Security: Which Binding to use in Internet based WCF Application?

Filed under: wcf — Tags: , — adiil @ 10:37 am

 

Recently I did some diving in WCF bindings to figure out which binding to use in different kinds of scenario and what are the security implications of it for a Internet Based WCF service. As WCF concerned, definitely there are loads of options and choosing the right one in the right scenario left to us to decide. I am still continuing my research for a internet based WCF service and jot down my findings in flowchart as below .Please bear in mind that this flowchart is far from complete at this moment. I will update it as I go thru different other bindings and/or scenarios:

 


 

Links to original files: Binding.gif & WCF_BINDINGS.vsd

Please do let me know if any question come up or any new ideas to update this flowchart. Thanks for visiting the blog. I will be waiting for valuable feedback.

Older Posts »

Blog at WordPress.com.