The the last post I showed how to obtain and deploy the new free SSL/TLS certificates from the Let’s Encrypt project. In this post, I’ll show how to defend your newly secured website against various weaknesses that lurk around SSL/TLS.

Test your site

The first thing to do is see what state your site is in. You can do this with the website SSL Labs. Enter your domain name and wait a few minutes while the magic happens. When finished your website will get an overall grade and a breakdown of how well it did in various areas. Most useful are the headlines warning you of various holes in your server setup. Here’s what my results looked like:

My first SSL Labs results

OK, got a C grade[1] for a default setup on my server software, Nginx. Not that good. Let’s see if I can improve on that.

Fix the POODLE attack

Let’s take a look at the first pink headline warning about the POODLE attack. That’s what caused the grade to be limited to C.

Now POODLE stands for Padding Oracle On Downgraded Legacy Encryption and is an exploit for the old SSLv3 protocol (18 years old) that allows parts of the encrypted data to be read. Not good.

The only way to fix this issue is to disable SSLv3 on the server-side. This will stop very old clients from connecting but also a crafty hacker from forcing a modern client to use SSLv3.

Here are instructions for disabling SSLv3 for some of the popular servers. Here’s what I did for my Nginx server. It’s just one line actually. Add this:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

to the server { } block that defines your virtual server you are securing. This limits the versions of SSL/TLS that your server is willing to use. Check the Nginx configuration and restart:

sudo nginx -t
sudo service nginx restart

Let’s run the SSL Labs test again...

Improved SSL Labs result. Grade B.

OK, that’s an improvement. A ‘B’. Let’s tackle the next issue.

Strengthening Diffie-Hellman

The next highlighted issue is about weak Diffie-Hellman (DH) key exchange parameters. DH is the basis of all the public-key encryption used on the Internet, but over time it has improved. So again, if our server supports old versions, it might be vulnerable to attack.

If you follow the ‘MORE INFO’ link in search of practical instructions, you get to this page. This page recommends three things:

  • Disable Export Cipher Suites - these are old weak ciphers the US allowed to be used outside the US. They didn’t want the rest of the world to use strong encryption.
  • Deploy (Ephemeral) Elliptic-Curve Diffie-Hellman (ECDHE) - basically, get your server to prefer the latest crypto algorithms.
  • Use a Strong Diffie Hellman Group - use long groups of at least 2048 bits and don’t use the common default prime numbers as a basis for the encryption cipher.

On to the practical steps for my Nginx server. First we need to create the parameters that define a new 2048 bit group (note this command make take a few minutes):

sudo openssl dhparam -out dhparams.pem 2048

If you are in your home directory, this will create the file dhparams.pem that the Nginx config file will reference. Put it somewhere sensible on you system. I did:

sudo cp ~/dhparams.pem /etc/ssl/

The next thing to do is add the following three lines to the virtual server server {...} block:

ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

ssl_prefer_server_ciphers on;

ssl_dhparam /etc/ssl/dhparams.pem;

The first line tells the server in what order to try the cipher suites when making a secure connection to the client. So no surprise that ECDHE ciphers are at the front of the queue. It also says never to use the very old and weak ciphers like MD5 or RC4. Again, this stops downgrade attacks.

The next line just says that the server should be in charge of the cipher preference and not listen to what the client prefers, as it may be compromised.

The last line defines where that dhparams.pem file can be found on you system.

Check the changed server configuration:

sudo nginx -t

If all is well, restart Nginx:

sudo service nginx restart

OK, great. Let’s run the SSL Labs test again...

Brilliant. We got an ‘A’ grade. That’s pretty much as good as it gets. While you can get an ‘A+’ grade, it’s only reserved for some exceptionally secure server setups, so would not be as simple to implement.

You’ll also notice that the warning about not supporting Forward Secrecy has gone, so that has be resolved too. If you server supports forward secrecy, it means that past encrypted communications will not be at risk of being decoded if the long-term keys are compromised. Nice.

Final reflections

So we’ve gone from a grade ‘C’ to a grade ‘A’, just by a few configuration changes and creating a 2048 bit based DH parameter file. Pretty good going. Strange then that if you look at the SSL Labs site, you see so many sites failing with grades ‘E’ or ‘F’. Out of date server software and poor configuration choices are mainly to blame.

It’s true that the above config changes have left some clients behind (such as IE 6 on Windows XP and Java 6), but these are tiny minorities that should not be allowed to impact the security of the majority.


  1. If you want to know how the grades are calculated, read this document. ↩︎