Improve SSL exchanges safety made by your web server

My personal website https://vincent.composieux.fr is available over HTTPS since a long time now thanks to Let's Encrypt. After having a look at test results and having a look at vulnerabilities I had to fix in order to gain a better score, I will finally share on this blog post how I fixed everything to get a A+ score.

This score will allow you to have a better security when exchanging keys and information between your server and your clients because it is computed depending on vulnerabilities you are open to.

What are these vulnerabilities?

Here is a list of most known vulnerabilities you have to fix:

CLR / OCSP: Initially, certificated validation was using the CLR method (Certificate Revocation List). Problem with this solution is that the list has grown considerably and now takes a long time to download. That's why you know have to use the Online Certificate Status Protocol (OCSP) which is really more lighter because only one record is returned and the verification process is delegated to the certification authority.

Logjam - Weak Diffie-Hellman (DH): This is a "man-in-the-middle" attack which allows to downgrade cyptography of TLS alhorithm to 512 bits in order to allow attacker to read and modify data which are transited. We will be able to fix this vulnerability by giving to our server a special key. We will see this later. For more information about this attack: https://weakdh.org.

SSLv2 et SSLv3: These SSL versions are vulnerable and so have to be disabled, that's why we will only enable non-vulnerable TLS protocols in our web server configuration. For more information about these vulnerabilities: http://disablessl3.com.

Some ciphers: Some ciphers suite also are compromised so you have to delete them from your web server configuration in order to allow trusted ciphers only. Please note that OpenSSL will only use the ciphers you can use in your current version so don't hesitate to put a full list.

Heartbleed: This recent vulnerability was published on april 2014 and occured in the OpenSSL cryptography. This is now fixed in recent versions. I invite your to update your OpenSSL versions. Here are the vulnerable ones:

  • OpenSSL 1.0.1 to 1.0.1f (included) are vulnerable
  • OpenSSL 1.0.1g is not vulnerable
  • OpenSSL 1.0.0 branch is not vulnerable
  • OpenSSL 0.9.8 branch is not vulnerable

In order to retrieve your OpenSSL version (and to update it if required):

$ openssl version
OpenSSL 1.0.1t  3 May 2016

Next, let's see how to fix these vulnerabilities in our web server configuration! I am personnally using Nginx but I also give your the Apache configuration in this article.

Virtualhost configuration

Let's start by updating your virtualhost configuration in order to specify it the ssl keys and certificate and also add a new HSTS header to it in order to specify that this website will only be available over HTTPS.

For Nginx:

ssl_certificate /etc/ssl/domain.tld/fullchain.pem;
ssl_certificate_key /etc/ssl/domain.tld/privkey.pem;
ssl_trusted_certificate /etc/ssl/domain.tld/chain.pem;

# HSTS (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;

For Apache:

SSLEngine             on
SSLCertificateFile    /ets/ssl/domain.tld/fullchain.pem
SSLCertificateKeyFile /ets/ssl/domain.tld/privkey.pem

# HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always set Strict-Transport-Security "max-age=15768000"

SSL Protocols and Ciphers

About Nginx, I invite your to store all the following configuration in a new /etc/nginx/conf.d/ssl.conf file. Next important step is to specify the protocols and ciphers you want to use on your web server (and mainly those you don't want to use).

For Nginx:

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

ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

For Apache:

SSLProtocol         all -SSLv3
SSLCipherSuite      ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on

OCSP Protocol

You have to clearly specify that you want to use it:

For Nginx:

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;

For Apache:

# OCSP Stapling, only in httpd 2.3.3 and later
SSLUseStapling                   on
SSLStaplingResponderTimeout      5
SSLStaplingReturnResponderErrors off
SSLStaplingCache                 shmcb:/var/run/ocsp(128000)

Diffie-Hellman (DH) parameters

For this fix, you have to generate a new key first (at least 2048 bits, I personnaly generated a 4096 bits one) that will secure key exchanges. I advise you to run it in a screen because it can be really long: 8 hours in my case:

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

Once the key is generated, update your web server configuration:

For Nginx:

# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
# openssl dhparam -out dhparam.pem 2048
ssl_dhparam /etc/ssl/certs/dhparam.pem;

resolver 8.8.4.4 8.8.8.8;

For Apache:

You will have to append to your SSLCertificateFile file the following DH PARAMETERS section:

-----BEGIN DH PARAMETERS-----
MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR
Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL
/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC
-----END DH PARAMETERS-----

For more information, you can go to Apache documentation: https://httpd.apache.org/docs/current/ssl/ssl_faq.html#javadh.

This is finished, I now advise you to run a configuration test first and then restart your web server and observe your new score on SSLLabs!

Conclusion

In the case you use another server, you also can have a look at this great tool proposed by Mozilla in order to update your configuration: https://mozilla.github.io/server-side-tls/ssl-config-generator.