mark nottingham

If You Can Read This, You're SNIing

Friday, 9 May 2014

HTTP

When TLS was defined, it didn’t allow more than one hostname to be available on a single IP address / port pair, leading to “virtual hosting” issues; each Web site (for example) now requires a dedicated IP address.

HTTP solved this problem with the Host request header; TLS did it with the Server Name Indication (SNI) extension. You can read more about it at the Wikipedia page.

The problem is that some clients – most notably Windows XP of any flavour, Android 2.x, and Java up until 1.7 – don’t send SNI information. Since requiring SNI effectively orphans these clients, people have been reluctant to require it on their Web sites, even though it saves precious, precious IPv4 addresses.

An Experiment

However, I believe in living on the bleeding edge, want to get more deployment experience with the protocols we’re developing, and most importantly, don’t want to give Rackspace the extra $2 a month for another IP address.

So, both this site and redbot.org have switched to HTTPS URIs, and require the use of SNI to access them. My audience tends not to run Windows XP, so I think that’s a reasonable thing to do, and somebody has to take the first step.

(BTW - for those who think this site may have got a bit slower, it’s not because of the TLS – it’s because I moved the server from Texas to Sydney.)

Along the way, I tried to get reasonably close to best practice for both security (as outlined by bettercrypto.org) and performance (see Is TLS Fast Yet?). Once things settle down a bit more, I’ll turn on Strict Transport Security too.

The SNI configuration for Apache 2.4 was a bit fiddly, mostly because I didn’t want to set a “default” site for clients that don’t send SNI; I wanted a hard fail. The relevant config ended up looking like this:

SSLStrictSNIVHostCheck on
ErrorDocument 403 "TLS SNI Required."
Listen 443
<VirtualHost *:443>
  ...
  SSLStrictSNIVHostCheck on
  <Directory ...>
    ErrorDocument 403 default
    SSLRequireSSL
    SSLOptions +StrictRequire
  </Directory>
</VirtualHost>

In my testing, this generates a 403 with the message “TLS SNI Required.” for clients that don’t send SNI information.

403 really isn’t the greatest status code for this semantic, so I filed a bug with Apache to make it more appropriate, and to give more flexibility in the error document (since most people’s reaction to that message will be, deservedly, “huh?”).

Stories from the Logs

Interested to see what the effect of requiring SNI would be, I set my server up to log the server name presented:

LogFormat "%h %t %D %u %{SSL_TLS_SNI}e \"%r\" %>s %R %b %X %I %O \"%{Referer}i\" \"%{User-agent}i\"" site

Clients that don’t present SNI get logged as “-“, and of course get a 403.

After a bit of command-line grep / sort / uniq foo, here is a list of UAs that didn’t present SNI information. In some cases, I’ve trimmed the “helpful” compatibility information out (e.g., Mozilla/blah…). I’ve also taken out the browsers that don’t support SNI (almost all on XP or older versions of Windows).

Sites, Services

These are online sites and services that made fetches without SNI, where I can’t determine what their implementation language is.

Seach Engines

Really just a sub-category of Sites and Services, search engines that didn’t send SNI include:

Tools

These ones look like desktop or mobile tools, but I can’t tell the implementation language.

Unknown

Not sure about these. shrug

Language-Specific

Finally, agents that can be tracked to a specific implementation language.

Java

Java supports SNI since 1.7, but of course there are still some old clients out there:

Perl

Apparently, Perl IO::Socket::SSL has supported SNI for a while now, provided that the underlying OpenSSL does. These people should just need to upgrade OpenSSL and rebuild their Perl.

PHP

PHP gave control over SNI in 5.3.2, but if they’re using Curl, it’s just a matter of getting the right versions.

Ruby

It looks like Ruby has supported SNI for a while now. Not sure what’s going on here.

Python

Later releases of Python 3 have SNI, and Python 2 should be getting it in the next few weeks, when 2.7.7 is released. Hopefully these folks will upgrade and this list will thin down soon:

Conclusions

It’s early days, of course, but this makes me pretty hopeful; if Python gets fixed soon, it knocks out a fair bit of the list, and there’s a small-ish list of sites and services that needs to upgrade (which is dwarfed by the list of those that do support SNI, btw).


2 Comments

openid.seld.be said:

Regarding Windows XP and client support, your article has a few inaccuracies that make it sound worse than it is. First of all only Internet Explorer is concerned. If you use Chrome or Firefox you should have no problem. Secondly as far as I know Windows XP with Service Pack 3 actually started supporting SNI. I am not sure why the wikipedia page does not mention this anymore, it used to.

In any case, my experience from running two moderately high traffic sites with SNI for a while was that it all works pretty well except for CentOS 5 machines that still run with a very old curl. I ever had one XP user complain and after updating to SP3 (which is really a good idea if you are concerned about security at all) it seemed resolved.

Saturday, June 7 2014 at 9:09 AM

yuhong.wordpress.com said:

“Secondly as far as I know Windows XP with Service Pack 3 actually started supporting SNI. I am not sure why the wikipedia page does not mention this anymore, it used to.” It does not support SNI.

Monday, June 30 2014 at 4:50 AM