WCF Security: WCF Performance & ProtectionLevel – Part 2

In the previous post, we have stated the several problems not being able to configure ProtectionLevel for different endpoint declaratively using configuration files. In this post, we address this issue and thereby, describe how to specify ProtectionLevel for multiple endpoints of a service using .config file.

Outline. In this post, we start by stating motivation of specifing ProtectionLevel for multiple endpoints of a service declaritvely instead of programmatically. Then, we discuss the steps to achieve it.

Motivation: ProtectionLevel for Multiple Endpoints

Basically, ProtectionLevel enforces a security requirement on request and response messages in the channel, and all the consumer of the message must conform to that requirement; anything otherwise results in runtime exception. In the last post, we have described how to configure ProtectionLevel at different level of WCF messaging stack and observed that it can only be set programmatically in the contract of a WCF service, which unfortunately has impacts on all the preconfigured bindings.

For instance, consider that we would like to have two different endpoints to use different ProtectionLevel. In addition, we want to make it configurable so that we can the security behavior of the endpoint conveniently after it has been deployed.

Are these requirements practical? To answer that, consider following case: we have only one endpoint and we are using message level security with wsHttpBinding (or ws2007httpbinding preferable one for internet based WCF Service). For internet users consuming this service, we are using ProtectionLevel.EncryptAndSign because of the security requirement imposed for our application. However, in case of local intranet, we 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 requests and responses. Most importantly, we don’t need ProtectionLevel.EncryptAndSign for the messages in this context as per security policy. Out of the box, there is no features available that can enable the use of different ProtectionLevel in these cases.

Obviously, there is one naive approach to host to service twice by compiling the code in 2 different ProtectionLevel. At 1 to 10 scale, how would you rate this solution ? Ok , then let’s move on…

Thus, what we need is to make two different endpoints to work with different ProtectionLevel, and using custom endpoint behavior, it can be achieved. Thus, the internet users will be able to use the wsHttpBinding with default ProtectionLevel, while the intranet users use the less secure– ProtectionLevel.Sign. The next section shows how to achieve this.

ProtectionLevel Configuration via Custom Endpoint Behavior

To do this, we have following these steps.First we have to create a Custom EndpointBehavior by implementing IEndpointBehavior as below –

Then, we create a BehaviorElement by extending BehaviorExtensionElement to make the behavior configurable through config file.

Thus the coding part this done. Let’s start configuring. 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 :

Then, we create a endpoint behavior like below:

Now, if we need to use a similar ProtectionLevel that we configured at the previous step in any endpoint , we simply need to add it as behaviorConfiguration, and we are done.

More on MessageSecurityBehavior

So far, we have described how to configure ProtectionLevel at runtime. Next we explain MessageSecurityBehavior. By changing the ChannelProtectionRequirement of an Endpoint, the new custom behavior impacts requests and responses of the channel. Moreover, the contract also binds to the configured ProtectionLevel. Then, the two different MessagePartSpecification was created, where 1st one is an empty MessagePartSpecification, and 2nd one refers to the MessagePartSpecification which contains body.

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

For instance, 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

In this post, we show how to declaritively specify the ProtectionLevel for multiple endpoints exposed by a WCF service. Though it’s not difficult to update the ProtectionLevel at runtime, we must note that client and server always conform to the ProtectionLevel requirement, and as a consequence, updating the ProtectionLevel at runtime might results in updating the clients configuration/code.

Additional Links

  1. WCF Security: WCF Performance & ProtectionLevel – Part 1 : https://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
Advertisements

WCF Security: WCF Performance & ProtectionLevel – Part 1

After experimenting a bit further with WCF performance, it became clear that if we want to increase performance of a WCF service hosted on internet, given that it must support digital signature, where that data is not that sensitive, we can opt for ProtectionLevel.None for the wsHttpBinding. Following comparison for a typical WCF service shows that using ProtectionLevel.None, wsHttpBinding is performing quite well:

This result infers to the fact that encrypt and sign operation definitely take additional time in every request and response.

More on ProtectionLevel

Using ProtectionLevel attribute , we can do following–

  • We can impose 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.

Consequently, we interpret ProtectionLevel as a mean to enforce consumer of the service to comply with that particular security standard. That is, in the service side we can set the ProtectionLevel = ProtectionLevel.None, the is, the consumers of the service can use anything above it, such as ProtectionLevel.Sign, or ProtectionLevel.EncryptAndSign.

How can we configure it ?

If we are using a transport binding e.g., nettcpBinding, we can change ProtectionLevel using the <binding> configuration–-

However, we cannot specify ProtectionLevel via declaritive configuration in case of some binding such as– wsHttpBinding or basicHttpBinding. In fact, it can only be configured programmatically, as shown below:

So, we cannot change the ProtectionLevel of these bindings with message level security via configuration after it has been deployed. Furthermore, we can not specify different ProtectionLevel for different bindings as we need to specify it at the Contract Level in the code. However, there is way to do it which we discuss in the next post.

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

Specifying a ProtectionLevel at the top level have impact at all the levels below, unless it is overridden. For example , we can specify ProtectionLevel like as follows.

Even if at the ServiceContract , ProtectionLevel requirement is EncryptAndSign, we override it in GetSessionId by setting the ProtectionLevel requirement to None, i.e. the ProtectionLevel in the lower levels, such as at MessageContract, MessageHeader, and MessageBody will conform to the ProtectionLevel.None for GetSessionId, as it is shown in the request and response stream as follows.

On the other hand, GetSessionIdEncrypted will have encrypted and signed message in the wire, as it is specified at the OperationContract

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, isn’t it? :)

Note that, 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 instance,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 be encrypt & sign at the transport layer.

Conclusion

As we observe that ProtectionLevel is a important attribute with several implications, we must use it with due considerations.  Check out the next post, which describe how to specify ProtectionLevel for multiple endpoints of a service declaratively using a .config file.

Please feel free leave any comment. Thanks for visiting this blog.