Improving SSL/HTTPS Security to an A+

These sim­ple steps can improve your Qualys SSL Report to an A+:

Step 1: Getting my initial report (B):

You can get a Qualys SSL Report on any site. My rat­ing start­ed as a B with a rea­son­ably good set­up:

Step 2: Improving Ciphers List

SSL v2 is inse­cure, so it need­ed to be dis­abled, and SSLv3 also need­ed to be dis­abled as TLS 1.0 suf­fers a down­grade attack, allow­ing an attack­er to force SSLv3 dis­abling for­ward secre­cy. I updat­ed my nginx con­fig to use:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

I opt­ed to con­fig­ure this in the main nginx.conf file, rather than each domain, as I saw now rea­son I would make indi­vid­ual changes on a domain basis.

I also enabled ssl_prefer_server_ciphers and ssl_session_cache:

ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

And used this cipher suite which main­tains max­i­mum back­wards com­pat­i­bil­i­ty. Although I’m using SNI which isn’t sup­port­ed by IE6, I pre­fer my sites to be as back­wards com­pat­i­ble as pos­si­ble.

ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

I also added these lines:

ssl_prefer_server_ciphers on;
 ssl_session_cache shared:SSL:10m;

I retest­ed the site, and improved to an A rat­ing:

Step 3: Deffie Hellman Ephemeral Parameters

Diffie-Hell­man ensures that pre-mas­ter keys can­not be inter­cept­ed by Man In The Mid­dle attacks, and it is easy to enable in Nginx.

First gen­er­ate a stronger DHE para­me­ter… be pre­pared to wait around 15 min­utes for OpenSSL to gen­er­ate this cer­tifi­cate:

cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096

Then con­fig­ure Nginx to use it:

ssl_dhparam /etc/ssl/certs/dhparam.pem;

On retest­ing, I achieved the A+ grade!

Step 4: Add a DNS CAA record

The Cer­ti­fi­ca­tion Author­i­ty Autho­riza­tion (CAA) DNS record allows you to use your DNS records as a mech­a­nism to whitelist cer­tifi­cate author­i­ties that are allowed to issue cer­tifi­cates for their host­names.

To imple­ment this, I had to change from Ama­zon AWS Route 53, to Google Cloud DNS, as AWS shame­ful­ly doesn’t pro­vide CAA report.

I use Let’s Encrypt, and added this DNS record:

0 issue "letsencrypt.org"

Cur­rent­ly this is option­al, but it will be manda­to­ry from Sep­tem­ber 2017.

Step 5: Add HTTP Strict Transport Security (HSTS) Header

A head­er can be sent from your serv­er which will inform browsers to only make HTTPS requests. Browsers will no longer make HTTP requests until the head­er expires. This has two main ben­e­fits: a spoofed site with­out your SSL cer­tifi­cate will not be effec­tive, and sub­se­quent vis­its to your site will go straight to your HTTPS ver­sion with­out a redi­rect, mak­ing page load­ing faster.

Be sure to use a low expiry time while devel­op­ing your site, as once a brows­er caches the head­er, it is not pos­si­ble to clear it. Once you’ve sent this head­er, expect your site to be HTTPS in the long term, with no going back.

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

For devel­op­ment, use this short­er time:

add_header Strict-Transport-Security "max-age=360;" always;

There is a push to have browsers have a pre­loaded list of HTTPS/HSTS enabled sites, but the strict require­ments for sub­mis­sion require sev­er­al sub-domain redi­rects, which in my opin­ion would reduce over­all per­for­mance. I don’t see the harm in still send­ing the ‘pre­load’ para­me­ter.

 

Further reading: