Accessible yet secure NginX

For the more technical/geeky chat subjects!

Moderator: satrow

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 22155
Joined: Sun, 28 Aug 2011, 17:27
Location: 58.5°N 15.5°E
Contact:

Accessible yet secure NginX

Unread postby Moonchild » Tue, 07 Aug 2018, 00:57

Just thought I'd share the tuned NginX configuration with you all here that is used on this (https-exclusive) forum.
A few non-standard things in place (because of my preference for Camellia over AES as a symmetric cypher) but that can always be changed if you want to prefer the use of Rijndael-based cyphers.

Code: Select all

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.org;
    access_log off;
    error_log /path/to/error.log;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate        /etc/nginx/certs/mydomain.crt;
    ssl_certificate_key    /etc/nginx/certs/mydomain.key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers EDH+CAMELLIA:EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:AES256:HIGH:AES128:CAMELLIA:!RC4:!3DES:!SEED:!aNULL:!LOW:!MD5:!EXP;
    ssl_dhparam /etc/nginx/RSA4096.pem;
    ssl_ecdh_curve secp384r1;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

# Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 4.2.2.1 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    server_tokens off;
    add_header Strict-Transport-Security "max-age=31536000;";
    add_header X-Content-Type-Options "nosniff";
    add_header X-XSS-Protection "1";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header Referrer-Policy "strict-origin-when-cross-origin";

    server_name mydomain.org;
    access_log /path/to/access-ssl.log;
    error_log /path/to/error-ssl.log;
    root /path/to/public_html;
    client_max_body_size 25M;

[any specific location rules, e.g. for php, go here]

}


Running through the config and lifting out important bits:

The first server {} block makes sure to redirect any http requests to https (not logging these redirections). Any errors are still logged to catch oddities/abuse/attacks.
Straight-forward and shouldn't be difficult to understand.

Code: Select all

    listen 443 ssl http2;
    listen [::]:443 ssl http2;

Open port 443 (https) for TLS connections on both IPv4 and IPv6, and enable HTTP/2 on it.

Code: Select all

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

Provide TLS 1.2 connections with fallback to v1.1 and v1.0 for accessibility from older clients

Code: Select all

ssl_ciphers EDH+CAMELLIA:EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:AES256:HIGH:AES128:CAMELLIA:!RC4:!3DES:!SEED:!aNULL:!LOW:!MD5:!EXP;

This is the preferred cypher order on this server, giving preference to Camellia with ephemeral Diffie-Hellman key exchange. Although this exchange is relatively expensive (It uses fixed parameters and not an elliptic curve), the lack of ECDHE for Camellia in common crypto libraries due to political decisions rather than technical ones enforces plain DHE for this. This is still safe because of a large key at the root of it (see dhparam). I'm a proponent of Camellia as a symmetric cypher because, unlike AES, there are no known weakening attacks against it and it's adopted as a strong cypher by several leading crypto authorities in the world. (Firefox users are out of luck because Mozilla has specifically disabled this cypher even if NSS supports it).
Beyond that, preferring Elliptic Curve and Galois-Counter modes for cypher suites, sorting them in most secure to least secure order gives a very secure end result (forward secrecy is used in all supported clients). Weak/broken cyphers like RC4, 3DES, MD5-based HMAC, Export and low sec suites are all disabled.

Code: Select all

ssl_dhparam /etc/nginx/RSA4096.pem;

This is the pre-generated DHE parameter file using a 4096-bits RSA key. If you enable DHE-based cypher suites in your server, you should always generate these parameter files with sufficient size (at least 2048 bits) to prevent LOGJAM related weakness.
You can generate this with OpenSSL:
openssl dhparam -out RSA4096.pem -5 4096

Code: Select all

ssl_ecdh_curve secp384r1;

NginX doesn't use an optimal elliptic curve by default (opting for a fast one instead). This line makes sure a curve algorithm with higher security is selected for all EC exchanges.

Code: Select all

ssl_prefer_server_ciphers on;

We make sure our carefully-selected order in ssl_ciphers is used with this line.

Code: Select all

ssl_session_cache shared:SSL:10m;

Of course we want to make sure sessions are re-used to lower load on the server/reduce delays for visitors from re-establishing TLS all over again.

Code: Select all

# Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 4.2.2.1 8.8.4.4 valid=300s;
    resolver_timeout 5s;

This enables and uses OCSP stapling, one of the chief mechanisms for quick and secure verification of the TLS certificates in use without having to call out to OCSP servers from the browser (increases client privacy and performance). We're using Cloudflare, HE and Google DNS servers for resolving, which should provide plenty of redundancy for the required server->OCSP connections.

Code: Select all

    server_tokens off;

No need to broadcast what server and version we're using.

Code: Select all

    add_header Strict-Transport-Security "max-age=31536000;";

Enable HSTS for this domain with a sufficiently-long time-to-live.

Code: Select all

    add_header X-Content-Type-Options "nosniff";
    add_header X-XSS-Protection "1";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header Referrer-Policy "strict-origin-when-cross-origin";

This tunes miscellaneous headers to leverage client security features.
(If you want to know more about these headers, please inform yourself -- there are plenty of documents describing these features out on the web)

Result:
a+.jpg

And all supported clients (everything except IE/XP and old java versions, pretty much) will use forward secrecy.
Cypher strength is not maxed out on purpose, because we want to strike a balance here to keep maximum accessibility while not compromising security.

I hope this is of use to anyone out there :)
Last edited by Moonchild on Tue, 07 Aug 2018, 01:55, edited 3 times in total.
Improving Mozilla code: You know you're on the right track with code changes when you spend the majority of your time deleting code.

"If you want to build a better world for yourself, you have to be willing to build one for everybody." -- Coyote Osborne

User avatar
adesh
Astronaut
Astronaut
Posts: 564
Joined: Tue, 06 Jun 2017, 07:38

Re: Accessible yet secure NginX

Unread postby adesh » Tue, 07 Aug 2018, 18:05

Very reasonable and secure setup indeed.
I always liked Camellia (because of a better name :P, and of course it has technical equivalence with AES), but wondered why there are fewer libraries and online resources in its support. Now I know why. Thank you!
Last edited by adesh on Tue, 07 Aug 2018, 19:27, edited 1 time in total.

bgstack15
Hobby Astronomer
Hobby Astronomer
Posts: 16
Joined: Mon, 22 Jan 2018, 23:04

Re: Accessible yet secure NginX

Unread postby bgstack15 » Fri, 07 Sep 2018, 15:49

Thanks for sharing! This is a good, general-purpose nginx config. I used to know almost all of these settings for apache, but I don't manage web server configs anymore. I was doing it during nginx's rise in popularity, so apache was my only choice. If I were to stand up a new web server, I'd try nginx and just copy this to start. Bookmark'd!


Return to “Technical chat”

Who is online

Users browsing this forum: No registered users and 3 guests