Accessible yet secure NginX

General discussion and chat (archived)
User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35473
Joined: 2011-08-28, 17:27
Location: Motala, SE
Contact:

Accessible yet secure NginX

Unread post by Moonchild » 2018-08-07, 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 2018-08-07, 01:55, edited 3 times in total.
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

User avatar
adesh
Board Warrior
Board Warrior
Posts: 1277
Joined: 2017-06-06, 07:38

Re: Accessible yet secure NginX

Unread post by adesh » 2018-08-07, 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 2018-08-07, 19:27, edited 1 time in total.

bgstack15
Fanatic
Fanatic
Posts: 121
Joined: 2018-01-22, 23:04

Re: Accessible yet secure NginX

Unread post by bgstack15 » 2018-09-07, 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!

Locked