Niraj Bhatt – Architect's Blog

Ruminations on .NET, Architecture & Design

Category Archives: Windows Communciation Foundation

Securing WCF Compression via HTTPS

I had blogged some time earlier about making GZipCompression work for large messages over WCF. Though GZipCompression reduces the overall size of message, message per se is vulnerable from security perspective. To encrypt this message transfer via HTTPS you need to follow below steps:

1) Change BindingElement from httpTransport to httpsTransport

<gzipMessageEncoding innerMessageEncoding=”textMessageEncoding” />

<httpsTransport … />

2) Now you need to enable support in IIS 7 by adding a Binding for https as shown below:

iis732

(Note the above would require a certificate. Easiest way in which you can create it in IIS 7 is by clicking on root computer name and then going to Server Certificates in features view, edit it, to create a self signed certificate for development environment. If you are on IIS 6 you can refer to Step 5 below).

3) Repeat Step 1 for client’s app.config

4) Ensure that all service URLs are https in app.config

5) To create a dummy certificate (for development environment) open VS.NET command prompt & key in :
a) makecert -pe -sr CurrentUser -ss My -n CN=YourCertificateNameHere -sky exchange (Certificate will be created in Current User’s personal store. For more options on certificate generation click here.)
b) certmgr : This will open the Current User’s certificate store. Go to Personal & select the certificate you created in previous command & right click it -> All Tasks -> Export -> Select Private Key (.pfx) -> Enter your password -> select the physical path for export -> Finish.
You are ready to move around with certificate you just created (N.B. not selecting to export the private key will give you a public certificate with .cer extension)

6) Your certificate name has to match the machine name or you can change system32/drivers/etc/hosts to make 127.0.0.1 bind to certificate name. This is required because a self signed certificate is not trusted by default.

MCT Session Demos

I have uploaded my MCT demos on “Building Secure Web Services using WCF” on skydrive. Though this would require some configuration in terms of setting up database for Membership / Role provider & installing certificates hopefully it should still help you in getting started with WCF Security. Keep a close eye on security mode & credentials. You can find a comprehensive set of samples here.

Let me elaborate on each demo considering the mentor audience:

1) You start with basicHttpBinding & wsHttpBinding. Turn the Message Logging on at transport level with LogEntireMessage set to true. You can show participants the secure wsHttpBinding. N.B. by default wsHttpBinding uses Message security with Windows Credentials. Here you don’t require certificates for message security as windows credentials rely on SPNEGO. You can use ProtectionLevel at OperationContract to differentiate between Sign & EncryptWithSign. Also impersonation works only with Windows credentials & for it to work client must explicitly give rights.

2) For basicHttpBinding change the security mode to transport & try to browse to get an error. Configure a SSL certificate to ensure that transport is safe. Browse should work now.

3) Username for wsHttpBinding can use either custom provider or ASP.NET providers. As it turns out custom provider is much easier to demo – no configurations required. Over here the credentials is Username but you will still need a certificate for providing protection to message. So you provide Server Certificate & in case you are using a makecert certificate you need to enable PeerTrust on client side. Don’t forget to put the public key of server certificate in client’s Trusted publishers folder (Personal Store).

4) Certificate security for wsHttpBinding requires certificates both on client & server side.

5) Issued tokens provide a level of flexibility in terms of rich credentials. You can demo it with self issued cards through Cardspace using wsFederationHttpBinding.

Thanks for being such a wonderful audience. Hope to meet you guys soon. Love you all :) .

Speaking at MCT Summit 2009

I would be taking a session on – “Building Secure Web Services using WCF” at this MCT Summit. You can find the details about summit here. A brief introduction to my session is also there in the speakers list. To get there just search for my name :) . In couple of days I will post the link to download demos I am going to demonstrate. Hope to see you there.

Resolving XmlDictionaryReaderQuotas Error for WCF Compression using GZipEncoder with Custom Binding

To compress the WCF data transfered over the wire, Microsoft Samples contains a GZipEncoder. This encoder wraps TextMessagingEncoder applying GZip Compression on top of it (N.B. you can even wrap a Binary Encoder to enable compression on Images for instance).

But as you try to transfer a large object using GZipEncoder, you will run into the below error asking to increase maximum string length content:

Unhandled Exception: System.ServiceModel.CommunicationException: Error in deserializing body of reply message for operation ‘GetData’. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 192, position 30. — System.Xml.XmlException: The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.

This can look quite confusing if you are not familiar with how WCF Channel pipeline works. This error is encountered by many even if you are not using GZipEncoder outlined above. So let’s look at all solutions while using & not using GzipEncoder (below I set the limit to max allowed, though it’s not recommended) :

1) Standard Binding (No GZipEncoder)
<bindings>
      <basicHttpBinding>
        <binding>
          <readerQuotas maxStringContentLength=”2147483647″/>
        </binding>
      </basicHttpBinding>
</bindings>
//new BasicHttpBinding().ReaderQuotas.MaxStringContentLength = Int32.MaxValue
N.B. Binding is a collection of channels providing an abstract way to add readerQuotas.

2) Custom Binding (No GZipEncoder)
<bindings>
      <customBinding>
        <binding>
          <textMessageEncoding>
            <readerQuotas maxStringContentLength=”2147483647″/>
          </textMessageEncoding>
          <httpTransport />
        </binding>
      </customBinding>
</bindings>

/*
CustomBinding binding = new CustomBinding();
TextMessageEncodingBindingElement element = new TextMessageEncodingBindingElement();
element.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.Elements.Add(element);

*/
N.B. For CustomBinding you need to select channels manually and for encoding channel you can specify the readerQuotas.

3) Using GZipEncoder – in this case you need to add couple of lines in GZipMessageEncodingBindingElement class (GZipMessageEncodingBindingElement.cs file). The method which you would change is below:

public override IChannelFactory BuildChannelFactory (BindingContext context)
{
if (context == null)
throw new ArgumentNullException(“context”);
context.BindingParameters.Add(this);

var property = GetProperty<XmlDictionaryReaderQuotas>(context);
property.MaxStringContentLength = 2147483647; //Int32.MaxValue
property.MaxArrayLength = 2147483647;
property.MaxBytesPerRead = 2147483647;

return context.BuildInnerChannelFactory();
}

N.B. It’s not possible to alter these parameters through configuration file while using GZipEncoder.

Hope this helps :) .

WCF Certificate Security with XBAP / IIS Issues

wsHttpBinding uses Message Security by default. But the default clientCredentialType is Windows. Now considering that your clients are going to access your application over internet, it makes sense to use Certificate / Username security. In my case I was using an XBAP in full trust and it was a more of fixed clients business scenario, so I thought of making use of the same certificates to provide secure transfer of data. Steps for doing the same are provided below:

1) Change clientCredentialType to Certificate (this would require you to customize wsHttpBinding) & specify the serviceCertificate in serviceCredentials of the web.config file. (N.B. The service can pick the certificate only from Local Machine and this can be the same certificate you are using to provide full trust to XBAP).

2) Next using Add Service Reference, generate proxy for the client. After generation you need to specify the location of the client certificate (this certificate would in Current User certificate store on client’s machine & different one from what we selected in step 1 – ideally used for authenticating client to service). This can be done by specifying new endpoint behavior on the client side.

3) As a final step in the client’s app.config file you need to change value:

<endpoint … >
<identity>
      <dns value=”YourCertNameHere” />
</identity>
</endpoint>

Plus if you are using self issued certificates through (certmgr.exe), you will need enable PeerTrust in service’s web.config and client’s app.config (search for authentication certificateValidationMode and set it to PeerTrust)

<authentication certificateValidationMode=”PeerOrChainTrust” />

(N.B. If you hosting your service on IIS & running under ASPNET/NETWORKSERVICE account, you would have to grant rights to that certificate so that IIS can access it when required. This would require you to download FindPrivateKey (I found it here) and execute below commands:
1) findprivatekey My LocalMachine -n CN=localhost –a
2) Output – (C:\Documents and Settings\All Users\ApplicationData\Microsoft\Crypto\RSA\MachineKeys\
7b90a71bfc56f2582e916a51aed)
3) cacls “C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys\7b90a71bfc56f2582e916a51aed” /E /G ASPNET:R
(Change ASPNET in step 3 to NETWORKSERVICE – For Windows Vista IIS7))


Follow

Get every new post delivered to your Inbox.

Join 178 other followers