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?
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>
: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:
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!
My solution is this:
If an old browser without SNI tries to access https://www.example.com/* then it will throw a error on the browser first, which cannot be avoided since until apache replies to a non-SNI browser it doesn't know which site it is asking for. Then it redirects to a page telling the user their browser is too old (as long as user clicks continue to website).
And for users with new browsers I have
That excludes most of the old browsers, including some like MSIE 5-8 on Vista (9+ is only Vista/7 so supports SNI). It's not 100% (symbian is ignored etc.) but should work for the majority. The minority can still choose to accept the certificate error.
As far as I'm aware there's not really a good way to do this -- You can use a mod_rewrite rule or similar conditionally based on the
User-agent
header, but it would have to be on a NON-SSL vhost: If the browser does not support SNI and it goes to a secure (https://
) site it's going to get the old-school Apache behavior of "Here's the first SSL certificate I have associated with that IP address -- Hope it's what you wanted!" -- If that's not the certificate the browser was expecting you'll wind up with an error message about hostname mismatches.This basically means people have to hit a non-SSL interstitial page that will redirect them - possibly exposing any data they're sending in their request. This may or may not be a deal breaker (you say you're going to send them to a non-SSL site anyway if they don't support SNI, so I assume you don't care that much about security. If I were designing a system that had a need for SSL as an encryption or authentication layer I'd be a bit more insistent about it though...)
None of that stops someone from bookmarking the secure site though - and if they use a shared bookmark service or restore their bookmarks to a machine where the web browser doesn't support SNI they're back in the Potential-for-SSL-Errors case.
I'd be tempted to solve this one of three ways:
RewriteRule
based onUser-Agent
headers.<SCRIPT>
tag on a non-default VHost; if the load succeeds, it's a bit of JS that reloads the whole page under HTTPS.Of these, I personally like #2 the best, but that involves modifying your sites' code.
Just for anyone needing it.
If you have multiple hosts and want all them to be SSL-enabled in VirtualHosting (and you bought a certificate for each) try the new
mod_djechelon_ssl
Usage:
As I posted here, you can only test for SNI support prior to requiring it. That is, you cannot force users onto SNI HTTPS and then fall-back if they don't support it, because they will receive an error like this (from Chrome on Windows XP) with no way to proceed.
So (unfortunately) the user has to actually begin over an insecure HTTP connection and then be upgraded only if they support SNI.
You can detect SNI support via:
Remote script
From your plain HTTP page, load a
<script>
from your destination SNI HTTPS server and if the script loads and runs correctly, you know the browser supports SNI.Cross-Domain AJAX (CORS)
Similar to option 1, you could try performing a cross-domain AJAX request from the HTTP page to the HTTPS, but be aware that CORS has only limited browser support.
Sniff the user-agent
This is probably the least reliable method, and you will need to decide between having a blacklist of browsers (and operating systems) known not to support it, or a whitelist of known systems that do.
We know that all versions of IE, Chrome & Opera on Windows XP and below do not support SNI. See CanIUse.com for full list of supported browsers.