Search code examples
nginxbrowserhttpswindows-xpsni

Redirecting non-SNI browsers to HTTP-only warning page in nginx


When using an SNI-only certificate (Let's Encrypt, CloudFlare free), users who are using Windows XP with Chrome or IE are not able to connect to your site. Firefox on XP works fine.

I would like to test if the user agent is Chrome on XP or IE on XP (or anything on XP which is not Firefox), and redirect them to a HTTP warning page which tells them to use Firefox on XP.

How would you do that under nginx?

At the moment, I'm using this block to redirect all http links to https.

if ($http_cf_visitor ~ '{"scheme":"http"}') {
    return 301 https://$server_name$request_uri;
}

How can I combine the above user agent detection into this block so non-SNI users are redirected to a HTTP only warning page?


Solution

  • You can use nginx user agent maps to detect and redirect non-SNI clients (IE and Chrome browsers on XP). Just put this to the site configuration file (outside server block):

    map $http_user_agent $is_xp {
        default 0;
        "~Windows NT 5.1" 1;
    }
    
    map $http_user_agent $whitelist_browser {
        default 0;
        "~Firefox" 1;
    }
    
    map $is_xp$whitelist_browser $no_sni {
        default 0;
        "10" 1;
    }
    

    The first map checks for Winhdows NT 5.1 in user agent string (=Windows XP), but because Firefox does not rely on XP's SSL implementation and has its own lib with SNI support we should better whitelist this browser even on XP and that is what the second map does. The third map just combines those two conditions together.

    So now we we can use it in server block to do what we want:

        if ($no_sni = 1) {
            # do whatever (redirect...???)
        }
    

    BUT!!! This solution works only for visitors that are typing your URL directly to address bar (browser defaults to HTTP). Imagine situation that Google (or whoever) crawls your site, detects it as HTTPS (bot's user agent is not XP nor IE) and of course indexes it as HTTPS and it will show it as HTTPS on search results page! So user with NON-SNI client will be redirected directly to HTTPS from search and you are in trouble again.

    The only workaround is to request one big certificate from CA (letsencrypt, ...) with all domains hosted on your server listed as SANs and use this certificate as default SSL cert. So if any non-sni client accesses your server it will get this universal certificate with all domains and everything will be OK.