I will need to use SSL SNI, but unfortunately from a recent Cloudflare blogpost only 90% of the network supports it. How can I (for example, with nginx) detect if the client supports SNI and provide/redirect to the HTTP version of the website? Is this possible? How else can I not lose the 10% of the traffic using SNI? Is it correct to assume that I wouldn't be able to redirect HTTPS traffic to HTTP without a valid certificate, and thus this request is impossible?
Thank you.
If you want to offer HTTPS from start you must provide a certificate accepted by the client from start. Because otherwise the client will not accept the SSL connection and you will not be able to redirect the client to a different site or a HTTP-only version. This means to support this case you
If you don't need to have HTTPS from start, that is if the client usually connects first with plain HTTP, then you could try to detect SNI support so that you can redirect the client later. This might be done by including an image, some JavaScript or similar stuff from your HTTPS-site and if the loading succeeds then you know that the client either supports SNI or ignores certificate errors.
Of course this leaves everything open to man-in-the-middle attacks, because all the man-in-the-middle has to do is to serve some different certificate or make HTTPS unavailable at all, because in this case you will never try to upgrade the connection to HTTPS. Additionally this can be used to make it look like the clients supports SNI, if the man-in-the-middle does it instead. And not only non-SNI clients are affected by this but SNI-capable clients can only be intercepted. So while this would be possible in theory it is not recommended because you can simply man-in-the-middle everything and thus make the main point of using HTTPS moot.
As I posted on StackOverflow, 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.