Search
Latest Articles
Richard Costall - Richard receives an new version of the Packt title Silverlight 5 Data and Services Cookbook. How does it measure up, Buffet or Banquet?
Richard Costall - Richard Costall's just released his second article covering Silverlight Out-Of-Browser, featuring Elevated Trust on the Simple Talk Website.
Skip Navigation Links
Login / Register
Article Quote
"WS-Security is particularly useful here, as it only encrypts message body"
Chris Seary
 Member Quotes
 Latest Articles
Silverlight 5 Data & Services Cookbook
Richard receives an new version of the Packt title Silverlight 5 Data and Services Cookbook. How does it measure up, Buffet or Banquet?
Silverlight OOB - Article 2 on SimpleTalk
Richard Costall's just released his second article covering Silverlight Out-Of-Browser, featuring Elevated Trust on the Simple Talk Website.
Man V Review Challenge
It's the Man V Review Challenge Richard Costall V 1,700 pages of APress's C# 2010 Platter feast for 10 -There can be Only 1 Winner.
APress XNA 3.0 Programming review
Richard gets his hands on a slightly old, but non the less useful book on XNA programming, find out what his thoughts were....
Silverlight Out Of Browser
Richard Costall's just released an article covering Silverlight Out-Of-Browser Basics on the Simple Talk Website.
Articles...
Conferences Conferences
Mix11
Mix11
Partner Showcase Partner Showcase
Ridgian are a leading IT solutions provider, delivering business centric solutions.
Ridgian are a leading IT solutions provider, delivering business centric solutions.
Powered by ASP.NET 2.0
NxtGenUG Article
Chris Seary Sunday, December 14, 2008
Chris Seary returns with another great article on Security. This time he shows us how to use encryption to encrypt just the data you want in WCF.
The Article 

Granular Security with Windows Communication Foundation

Issues with network protocol security

Security can be applied via network protocols. For instance, IPSec can be applied at the IP layer of the TCP/IP stack. Also, at the application layer, SSL can be used.

Both of these mechanisms encrypt the entire communication, providing confidentiality and integrity.

However, this can present problems. To inspect firewall traffic, it is necessary to decrypt the communications at the firewall. It may be necessary to then encrypt it again before it reaches the destination server. Also, network monitoring of traffic can be problematic, as the communications cannot be read until they reach the destination. SSL and IPSec encrypt the entire communication, rather than just sections of it.

Solutions using WS-Security

WS-Security is particularly useful here, as it only encrypts message body, rather than the entire packet sent across the network.

Imagine a situation where details of an account holder are passed across the network. It would be prudent to encrypt data such as the credit card number. However, it would be useful to be able to monitor the name of the account holder, and not have their name encrypted.

Implementation using Windows Communication Foundation

How can we encrypt only the credit card number?

Conventionally, a DataContract is used to form the contract for the WCF communications.

    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }

However, in this case, we're going to use the MessageContract, as it has an extra property within its attribute that we're going to use. The MessageContract is used when we need finer control over the shape of the SOAP message that we're sending.

[MessageContract]
    public class CompositeMessage
    {
        string _accountFirstName = string.Empty;
        string _accountSecondName = string.Empty;
        string _creditCardNumber = string.Empty;

        [MessageHeader(ProtectionLevel = System.Net.Security.ProtectionLevel.None)]
        public string AccountFirstName
        {
            get { return _accountFirstName; }
            set { _accountFirstName = value; }
        }

        [MessageHeader(ProtectionLevel = System.Net.Security.ProtectionLevel.None)]
        public string AcountSecondName
        {
            get { return _accountSecondName; }
            set { _accountSecondName = value; }
        }

       
        [MessageBodyMember(ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign)]
        public string CreditCardNumber
        {
            get { return _creditCardNumber; }
            set { _creditCardNumber = value; }
        }
    }

This extra property is the ProtectionLevel. It has three possible values: None, where the value is sent in the clear. Sign, where a digital signature is applied. Finally, EncryptAndSign, where the value is encrypted as well as digitally signed.

We can also decide whether we want to place values in the SOAP header or the SOAP body.

In this case, we've used the MessageHeader attribute where we want the data in the SOAP header,and the MessageBody attribute where we need the value placed into the SOAP body. This is done to make it easier to examine the SOAP message later in the article.

We're placing the firstname and the secondname in the header, and leaving them unencrypted.

The credit card data is encrypted and placed in the body.

Here is the method on the service.

public CompositeMessage GetDataUsingMessage(CompositeMessage composite)
{

       composite.AccountFirstName += "Fred";
       composite.AcountSecondName += "Bloggs";
       composite.CreditCardNumber = "123456789";

       return composite;
 }

On our data form, a button click event calls the service.

        private void MessageContract_Click(object sender, EventArgs e)
        {
            ServiceReference1.Service1Client sv1 = new ServiceReference1.Service1Client();

            string accountFirstName = string.Empty;
            string accountSecondName = string.Empty;
            string creditCardNumber = string.Empty;

            sv1.GetDataUsingMessage(ref accountFirstName,
                ref accountSecondName,
                ref creditCardNumber);
            string display = "First name is " + accountFirstName
                + " second name is " + accountSecondName
                + " credit card number is " + creditCardNumber;
            MessageBox.Show(display);
        }

Notice that the properties of the MessageContract are passed by ref.

This is the configuration file for calling the service. Nothing special here - it was generated by Visual Studio.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
           <endpoint address="http://wibble/HostDemoService/service1.svc"
    binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1"
    contract="ServiceReference1.IService1" name="WSHttpBinding_IService1">
            <identity>
              <dns value="localhost" />
            </identity>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Here is the result.

In order to observe the actual SOAP communication, install Fiddler on your system. It can be downloaded from this address:

http://www.fiddlertool.com/fiddler/

This is an HTTPDebugging proxy that you can use to monitor traffic.

To make it easier to read, the data from the 'TextView' window has been placed into Explorer, with its automatic formatting of XML.

You can clearly see the AccountFirstName and AccountSecondName values have been placed in the header, and are in the clear (unencrypted).

What about the cerdit card number?

All we can see here is the CipherValue in the body, which contains the encrypted data.

How was it encrypted?

We've achieved our result, which was to send the first name and second name in the clear, and encrypt the credit card data.

But if we look at the config file from the last section, we can't see any certificates mentioned. So how was the data encrypted?

If you look back to the screen shot of Fiddler, you can see there were four communications captured (see the window on the left of the Fiddler screen). What's happened is that a key negotiation handshake was used to create a symmetric key for the communications.

You can use this key exchange method when communicating between Windows servers, giving you encryption without the bother of handing out certificates. This is not useful for digital signatures, but is valuable if confidentiality is your main concern.

Summary

We've found out how to encrypt just a part of the message sent, and take control of the SOAP that's sent when using WCF to communicate.

Also, we've found that we can encrypt communications between Windows servers without having to manage keys.

I hope this article gives you food for thought for protection of your communications.

About Chris
Chris Seary is an independent security consultant, and is Director of Chris Seary Computing Ltd (www.seary.com). He has worked with many different Microsoft technologies, and for the last few years has specialised in the security aspects of enterprise-level .NET and Java systems.

He regularly contributes to forums, writes articles and white papers, and has a blog devoted (mainly) to IT security (http://blog.searyblog.com/).
Copyright © 2006-2009 NxtGenUG - Powered by ASP.NET 3.5