SSL, IIS, and Host Headers
By Brian
There is a lot of confusion about how IIS handles SSL. With all the confusion out there, I thought I should put together a quick post. This post will also explain the error message: At least one other site is using the same HTTPS binding and the binding is configured with a different certificate.
My discussions this week were specific to SharePoint, but the confusion is with host headers in IIS. The crux of the issue is that when IIS receives a request, the host header is encrypted. Therefore, IIS cannot determine which web site to route the request to.
Let’s start with a simple example without SSL. Say that I have two URLs http://www.brianbeach.com and http://blog.brianbeach.com. If I want to host them both on the same server, I have to set up bindings. I can tell IIS to listen on a specific IP address and port combination, or I can use host headers. See the image below.
If we look at the individual bindings, notice that IIS is listening on all IP addresses for any request to www.brianbeach.com on port 80.
So, how does this work? When your browser requests a page from www.brianbeach.com, it first resolves the IP address from DNS. Let’s say that IP address 192.168.1.2. Then, it sends a TCP packet to 192.168.1.2 on port 80. The body of the request looks like this.
When, IIS receives this request, it reads the last line, and routes it to the www.brianbeach.com site, based on bindings we configured above.
1 2 3 4 5 6 7 8
GET http://www.brianbeach.com/ HTTP/1.1 Accept: text/html, application/xhtml+xml, */* Accept-Language: en-US User-Agent: Mozilla/5.0 Accept-Encoding: gzip, deflate Connection: Keep-Alive Host: www.brianbeach.com
Herein lies the problem. Note that the host header (Host: www.brianbeach.com) only exists inside the body of the message. If I sent this request over SSL, IIS would not be able to read the host header until it decrypted the message. And, IIS cannot decrypt the message until it knows which site’s private key to use. Alas, a catch 22.
Therefore, it would seem that I cannot use host headers with SSL. In fact, notice that when I create an http binding, the host header is disabled. So, it would seem that, if we use SSL, we can only create bindings based on the IP address and port. In general this is true, but there is an exception: wildcard certificates.
A wildcard certificate is a certificate that can be used to secure multiple sub-domains. For example, a wildcard certificate, created for *.brianbeach.com can be used for both www.brianbeach.com and blog.brianbeach.com. Notice that when I select a wildcard certificate in IIS, the host header textbox is again enabled.
If you have been paying attention, you should be asking yourself: How does IIS know which certificate to use? Now I have two sites that both use the same certificate, but IIS still needs to decrypt the message to determine if it is destined for one of the two site that use this certificate. We could be hosting other site after all.
IIS does this based on the port number. You can only configure one certificate per port. First, IIS looks up the certificate based on the port the message was received on. Next, it decrypts the message and reads the host header. Finally, it uses the host header to route your request to the correct web site.
Note: that this only works with wildcard certificates and subdomains. I cannot host www.brianbeach.com and www.someothersite.com on the same server, because they do not use the same certificate. Also, note that wildcard certificates only work for a single level. Therefore, I cannot host www.blog.brianbeach.com using *.brianbeach.com.
BTW: Have you ever received the warning message below? When you try to configure a new https binding on a port that is already in use by another site, IIS warns you that you are about to change the SSL certificate for all sites listening on that port.