Apache2 SSL – Redirect to SSL Only if Browser Supports SNI

apache-2.2snisslvirtualhost

I have Apache 2.2 with mod_ssl and a bunch of sites in HTTPS on the same IP/port with VirtualHosting, so client must support SNI to connect to those virtual hosts.

I would like to configure my server the following way:

When a user types www.dummysite.com and his browser supports SNI (Server Name Indication), any HTTP request is redirected to https:// where an HSTS header is sent. But if the browser doesn't support SNI then the request is served by HTTP.

The above rule, stated as is, is actually a fallback rule for those people that still run old browsers, as Mozilla and Chrome don't have this problem, just to avoid leaving these users out of the site.

I would like to do this redirecting at the Apache config level, perhaps with a filter on the user agent. I wouldn't like to touch running applications except making sure that no direct http:// references are present (otherwise they imply a security warning)

[Edit] (while editing the question I forgot the question): what is the list of SNI-enabled user agents to redirect?

Best Answer

Since SNI occurs during the SSL/TLS handshake, it's not possible to detect browser support when the client connects to HTTP.

So, you're right; a user-agent filter is the only way to do this.

The big question is whether you want to act on a blacklist against browsers that you know won't listen for SNI, or a whitelist of browsers that are known to support it. Obscure or new devices being unable to use the site seems like a deal-breaker, so I'd say the whitelist might be the better option.

In your HTTP <VirtualHost>:

# Internet Explorer 7, 8, 9, on Vista or newer
RewriteCond %{HTTP_USER_AGENT} MSIE\s7.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s8.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s9.*Windows\sNT\s6 [OR]
# Chrome on Windows, Mac, Linux
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s6.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Macintosh.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Linux.*Chrome [OR]
# Firefox - we'll just make the assumption that all versions in the wild support:
RewriteCond %{HTTP_USER_AGENT} Gecko.*Firefox
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

Here's the blacklist option, too - keep in mind that this runs the risk of sending a client that doesn't use SNI to an SNI-needed site, but on the other hand, will send users of something new like IE 10 to the right place:

# IE 6
RewriteCond %{HTTP_USER_AGENT} !MSIE\s6
# Windows XP/2003
RewriteCond %{HTTP_USER_AGENT} !Windows\sNT\s5
# etc etc
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

There are a lot of browsers out there. I've been pretty loose with the expressions and haven't covered a lot of browsers - this could turn into quite the nightmare to maintain.

Whichever option you choose.. good luck!