Some Improvements to my NGiNX configuration


  • Sat 18 February 2017
  • misc

I recently became weary of errors of the form

{% raw %} Trusted domain error. "72.205.144.131" tried to access using "192.0.2.16" as host.

in my NextCloud logs. It turns out that there is a lot of random stuff out there that is just scanning the Internet, looking for things to poke at (my logs seem to suggest that it "knows about" NextCloud as well as OwnCloud, but it's using the IP address as the hostname, counting on people's adherance to the robustness principle and accommodation of old clients that speak the now-deprecated SSLv3 or otherwise don't support SNI to go ahead and route their https:// request through to somewhere interesting.

All of my clients (Macs, iDevices) support SNI. Here in the future do I care about screwing things up for folks who don't? That was a rhetorical question. I don't. People who are running IE6 on XP, or Netscape, or something similarly antiquated aren't in my general constituency for my blog, nor are they on the extremely short list of people who are using my NextCloud instance for calendar and contacts syncing.

After some investigation in NGiNX's documentation I came up with the following configuration snippets to add to my nginx.conf:

{% raw %} server { listen 80 default_server; listen [::]:80 default_server;

    server_name  _;
    return       444;
}

{% endraw %}

and

{% raw %} server { listen 443 ssl http2 default_server ; listen [::]:443 ssl http2 default_server ; server_name _; return 444;

    ssl_certificate /etc/ssl/local/bogus-server.crt;
    ssl_certificate_key /etc/ssl/local/bogus-server.key;

    ssl_dhparam /etc/ssl/local/dhparam2048.pem;

    ssl_session_cache shared:SSL:5m;
    ssl_session_timeout 10m;

    ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
    ssl_prefer_server_ciphers on;

    ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
}

{% endraw %}

I know you're probably wondering what's with that 444 since it's not an error code that's defined in any known HTTP spec. It turns out that 444 is an internal directive that's not seen by the client, that instructs NGiNX to ungracefully terminate the connection.

So what's with the bogus certs then? As it happens I already have a pair of self-signed certs with CN=bogusserver.seastrom.com. I use them when I don't have valid certs yet (or ever) lying around, yet need to give NGiNX a placeholder that actually passes the X.509 parser, so the daemon will come up. This approach is useful too for bootstrapping letsencrypt certificates - when you need a certificate before you have a certificate lest the server won't start.

Now, in order to be allowed through to talk to the server, you have to actually send the name of the web server you want to talk to as part of SNI, rather than just sending an IP address or an empty hostname. Security in obscurity? Not really, more like "keeping crud out of my logs in obscurity", not that different from running sshd on a non-standard port.

Going this far to deprecate support for old http stacks got me to thinking... in 2017q1 what would be the impact of ditching all of my non-TLS-1.2 support and cutting my cipher support way back? It turns out less than I thought. I stood up a test instance and ran the Qualys test suite against it. Nothing I couldn't live without, certainly for my calendar and contacts sync and probably for my blog as well.

Here are the new config fragments:

    ssl_protocols TLSv1.2 ;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

That upped my Qualys score a smidge, and sunset support for a bunch of old crufty browsers that I didn't care about anyway.

Onward!