Setting-Up WCF Over SSL on IIS 7.x

Monday, July 19, 2010 / Posted by Luke Puplett /

This is a short post is about the steps I had to take to switch an existing test WCF service over to a secure staging version that more closely mimics how it’ll be in the production environment. I hope to include some things they didn’t tell you in the instruction manual, mainly concerning the use of test certificates.

It’s stuff like this – configuring a secure web service – that makes me dislike WCF and IIS quite a lot. I liked Web Services, and Remoting, I even found raw sockets surprisingly easy but WCF is hard work. It’s the sort of thing that needs its own UI, management tools, and server, but to do this would arguably constrain its power.

  1. Add a self-signed certificate to the server by opening IIS Manager, highlighting your server name in the left pane and locating Server Certificates on the right and choosing Create Self-Signed Certificate then following the instructions.

  2. Add a new binding to your site for HTTPS and note that there’s no option for the host name.

  3. WCF cannot handle multiple bindings to the same scheme, as IIS and ASP.NET sites can, so if your WCF service is hosted downstream of your main site, such as from a virtual directory underneath your root domain and site, then add the following to your web.config which will filter the bindings so WCF sees just two:

    <add prefix="" />
    <add prefix="" />
  4. And now the bit that seems never to be explained and doesn’t seem to merit a proper UI in IIS, binding the certificate to the host header. Run this at a command prompt (one line):

    appcmd set site /"Main Site" /+bindings.[protocol='https',bindingInformation='*']
  5. Do not remove the original HTTPS binding. When I did, I got this error:

    An error occurred while making the HTTP request to This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.

  6. Now, if you’re using the built-in AuthenticationService, in your web.config or web.staging.config, make the following change/addition:

    <authenticationService enabled="true" requireSSL="true"/>
  7. Still in this document, find the binding element for the service and set it to use Transport security – the bottom lump of mine looks like this:

    <binding name="ssl">
    <security mode="Transport" />
  8. Close and save all that and then make the same change on the client. Personally, I don’t use config files for public ‘out there’ apps so the change is made within a service client factory using the following code:

    if (withSsl)
    basicBinding.Security.Mode = BasicHttpSecurityMode.Transport;
  9. Add the following non-WCF specific code at some point in your app which essentially just accepts any certificates as valid even if they’re downright dodgy (so make sure not to let it leak into production).

    #if DEBUG || STAGING
    System.Net.ServicePointManager.ServerCertificateValidationCallback = (se, cert, chain, sslError) => { return true; };
    _log.Warn("A pre-release option has been set: server certificates are no longer being checked for validity by this client app.");
  10. You do not need to add code that modifies the Authentication settings for the ServiceCertificate on the ClientCredentials object of a service client (ServiceBase<T>).

  11. Now test your service. You may want to use a tool like Fiddler to inspect the HTTP traffic.

Labels: , , ,


Comment by Luke Puplett on Sunday, August 29, 2010

In setting up another server, I was receiving the message "Could not find a base address that matches scheme http for the endpoint with binding BasicHttpBinding. Registered base address schemes .."

I thought I'd done everything. So I used appcmd.exe to check those bindings.

>appcmd list site /""

SITE "" (id:2,bindings:http/*,http/*,https/*:443:,state:Started)

Compare the output above to the correct output below:

SITE "" (id:2,bindings:http/*,http/*,https/*:443:,https/*,state:Started)

The last binding is https and also specifies the domain name - this basically meant I'd forgotten to run the appcmd.exe statement above (in the blog post). I'm still not really sure what it does and why we need to drop into DOS to do it, but its certainly very important.

If you're having a horrible time, then I share your pain brother. Sister?

Post a Comment