« Kick start my heart | Main | How many terrorists are there? »

November 22, 2004

Name-Based Virtual Hosts with SSL

Say you want to host multiple web sites on the same server. For instance, you want to have http://www.educatedguesswork.org/ go to this blog and http://www.ignorantcertainty.org/ go to its evil twin. Now, it's obviously easy to do if you have two machines, but that's not very efficient, especially if the web sites are fairly low traffic. What you want is virtual hosting--the appearance of having two servers on one physical machine.

There are two basic ways to make this work1. The first is to give the machine two IP addresses. You then have one virtual server listen on one IP and the other on the other (the exact implementation details don't matter). This is called IP-Based Virtual Hosting (IPBVH) and is the old-style way of doing things. The problem, of course, is that IP addresses are a scarce resource and so it's antisocial (and also kind of expensive) to grab enough IP addresses for every virtual host.

The modern way to do things is with Name-Based Virtual Hosting (NBVH). The way that this works is that the Web client provides the server's hostname in its HTTP request, like so:

GET / HTTP/1.1
Host: www.educatedguesswork.org:8080
User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.5) Gecko/20041118 Firefox/1.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Name-Based Virtual Hosting has two problems. The first is that it requires cooperation from the browser. That's not a big deal now because all browsers have done it for years. The second, larger, problem is that it doesn't work with SSL. The problem is that the SSL handshake happens before the first HTTP request is made, so the server doesn't know which certificate to use in its handshake. Because the certificate contains the host name (otherwise how would you know if you were talking to the right host?) this means that the hostname and cert generally won't match, which tends to freak users out. There is an update to SSL that puts the hostname in the SSL handshake (client cooperation again, naturally), but since it requires changes to the client it will be years before there's enough deployment to let you confidently use NBVH with SSL for most commercial applications.

There is, however, one situation in which NBVH with SSL works just fine--if you don't need the certificate to match the host. The most common situation where this applies is when you're using self-signed certificates rather than third-party certificates. In this environment, you either don't worry about active attack and don't have the users verify the certificate or have them verify the cert fingerprint manually and then trust it from there on (as in SSH). Even if you don't verify the certs at all, it's still better than not having SSL, and there's nothing wrong with the fingerprint method except that it's inconvenient.

In this mode, the server uses the same certificate for all requests, but then does virtual hosting for the HTTP portion. This works fine technically but it's a little hard to set up and the Apache documentation doesn't help much. However, Rob Austein and I got it working and here's an example of the relevant section of the httpd.conf file, with the comments removed:


AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl


NameVirtualHost 127.0.0.1:8443


SSLPassPhraseDialog  builtin
SSLSessionCache         dbm:/users/ekr/tmp/apache/logs/ssl_scache
SSLSessionCacheTimeout  300
SSLMutex  file:/users/ekr/tmp/apache/logs/ssl_mutex
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLLog      /users/ekr/tmp/apache/logs/ssl_engine_log
SSLLogLevel info
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /users/ekr/tmp/apache/conf/ssl.crt/server.crt
SSLCertificateKeyFile /users/ekr/tmp/apache/conf/ssl.key/server.key




##
## SSL Virtual Host Context
##

#  General setup for the virtual host
DocumentRoot "/users/ekr/tmp/apache/htdocs/lh1"
SSLEngine on
                                  


#  General setup for the virtual host
DocumentRoot "/users/ekr/tmp/apache/htdocs/lh2"
SSLEngine on
                                  

There are two keys to making this work:

  1. The NameVirtualHost directive which lets you use name-based virtual hosts at all.
  2. Putting SSLEngineOn in the virtual host directives.

Acknowledgements: Rob Austein and I worked on this together. I figured out how to make it work but I duplicated all of the SSL config directives in each VirtualHost clause. Rob figured out that you could move them to the main IfModule section, thus cleaning things up substantially.

1. There's actually a third way to make this work: use a separate port for each host. The problem with that is that it requires users to remember the port as well as the hostname, which is pretty unattractive.

Posted by ekr at November 22, 2004 5:32 PM | Filed under:

Comments

Most current browsers seem to support regular expressions (and not just wildcards) in the Common Name field. I wouldn't use it personally, but I've seen a lot of these certificates from browser CAs (at least I think so, I don't use these CAs and store all certificates manually).

By the way, IPv4 addresses for obscure HTTPS servers quite cheap because renumbering is usually not an issue (you just do it), and PA address space isn't exactly expensive for end users.

Posted by: Florian Weimer at November 23, 2004 9:26 AM

Is it possible to have the certificate bind the IP address rather than the host name? Would that satisfy browsers?

Posted by: Hal at November 23, 2004 9:56 AM

Regexps work a lot better if the domain names are related. Unfortunately, if you're running a hosting service, they're not. As for the availability of IPv4 addresses... They're not incredibly expensive but they're not free either. I'm paying like $5/month for the one the runs https://www.educatedguesswork.org/

Hal:
Putting the IP address in the cert doesn't protect you against active attack due to the possibility of DNS spoofing.

Posted by: EKR at November 23, 2004 10:26 AM

It would only take a few software packages adopting the TLS extensions for them to become commonplace:
IE, Mozilla, OpenSSL, MS Secchannel, IIS, Apache.

Everyone else will fall in line post haste.

Posted by: Mordy Ovits at November 24, 2004 10:03 AM

Unfortunately, I think this assessment is unduly optimistic. Certainly IE and Mozilla could deploy the extensions tomorrow but it takes the installed base quite some time to catch up.

Posted by: EKR at November 24, 2004 10:27 AM

I've used the third approach in a few situations - it actually works pretty well with conventional named-based virtual hosting since you can simply have the HTTP server redirect to the appropriate HTTPS service on a non-standard port. Since users almost never type https URLs in by hand this is surprisingly painless.

Posted by: Chris Adams at November 28, 2004 11:40 AM