Best Practical SSL Configuration

Updated: January 2019 with latest suggestions and revised commentary.

Updated: May 2016 with new cipher suggestions and revised commentary.

We routinely use SSL Labs to verify systems we’ve configured.  It’s a great service to verify that an SSL configuration is reasonably secure.  It  scores a site in four different areas:  Certificate, Protocol Support, Key Exchange, and Cipher Strength. A perfect score is theoretically possible, but isn’t practical because many client/OS combinations couldn’t connect to your site.

 

How do you maximize your score with a configuration that still allows nearly universal access?

Our goals are to:

1. Maximize the overall score from SSL Labs.
2. Ensure Forward Secrecy on the maximum number of clients.
3. Given #2, use the most secure cipher on each client.

We do allow AES128 as current thinking is it’s not less secure than AES256. You can drop this yourself by changing “AES” in our cipher list to “AES256”, but be aware that you will then drop some clients from AES128 to 3DES. You may have PHBs demanding “256 bit encryption”: Our cipher ordering keeps 256 preferred over 128, so clients that support 256 should be using it.

Our cipher preference order is:

1. ECDHE and AES GCM (256 before 128)
2. ECDHE and AES CBC (256 before 128)
3. DHE and AES GCM (256 before 128)
4. DHE and AES CBC (256 before 128)

We have further tweaked this cipher selection and ordering to support HTTP/2 in Firefox and other major browsers.

If you have any suggestions for improving this, or have configurations for more applications than we’re currently listing below, please comment and share!

Here’s our current approach:

1. Make sure your OpenSSL supports ECDHE, GCM, and TLS 1.2

You must be using OpenSSL 1.0.1+ to support TLS 1.2.   If your distribution isn’t shipping this, it’s time to consider a new distribution.

Check and verify that your OpenSSL supports TLS 1.2 and Elliptic Curve Diffie–Hellman.  TLSv1.2, GCM, and ECDHE are indicated below:

$ openssl ciphers -v | grep TLSv1.2
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
...
...
ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128)  Mac=SHA256
AES128-GCM-SHA256       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(128) Mac=AEAD
AES128-SHA256           TLSv1.2 Kx=RSA      Au=RSA  Enc=AES(128)  Mac=SHA256

If you’re not using a distribution that supports ECDHE, follow our article on compiling your own copy of OpenSSL here. Run away!

2. Force TLS 1.2+ Only

SSL Labs agent capabilities list that all current browsers on all current operating systems support TLS 1.2.

Apache:

SSLProtocol TLSv1.2

Nginx:

ssl_protocols TLSv1.2;

Postfix:

Warning: Many large legitimate mail servers do not support TLSv1.2 yet, even in 2019. 

Jan 26 05:12:54 server postfix/smtpd[23898]: Anonymous TLS connection established from newsletter42.walmart.com[161.170.248.83]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)
Jan 23 01:10:33 server postfix/smtpd[9209]: Anonymous TLS connection established from egssmtp04.att.com[144.160.112.13]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)
Jan 16 09:29:28 server postfix/smtpd[31353]: Anonymous TLS connection established from mta15.schwab.com[162.93.253.160]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)

(seriously Charles Schwab?)

smtpd_use_tls = yes
smtpd_tls_mandatory_protocols = TLSv1, TLSv1.1, TLSv1.2
smtpd_tls_protocols = TLSv1, TLSv1.1, TLSv1.2
smtp_use_tls = yes
smtp_tls_mandatory_protocols = TLSv1, TLSv1.1, TLSv1.2
smtp_tls_protocols = TLSv1, TLSv1.1, TLSv1.2

Dovecot:

ssl_protocols = TLSv1.2

Ejabberd:

listen:
  - 
    port: 5222
    ...
    ...
    protocol_options:
       - "no_sslv2"
       - "no_sslv3"
       - "no_tlsv1"
       - "no_tlsv1_1"

s2s_protocol_options:
       - "no_sslv2"
       - "no_sslv3"
       - "no_tlsv1"
       - "no_tlsv1_1"

3. Force a secure cipher list and cipher order preference

Apache:

SSLHonorCipherOrder on
SSLCipherSuite "ECDHE+AESGCM ECDHE+AES DHE+AESGCM DHE+AES"

Nginx:

ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE+AESGCM:ECDHE+AES:DHE+AESGCM:DHE+AES;

Postfix:

tls_high_cipherlist = ECDH+aRSA+AES256:ECDH+aRSA+AES128:AES256-SHA
smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
smtp_tls_ciphers = high
smtp_tls_mandatory_ciphers = high

Dovecot:

ssl_prefer_server_ciphers = yes
ssl_cipher_list = ECDHE+AESGCM ECDHE+AES DHE+AESGCM DHE+AES

Ejabberd:

listen:
  - 
    port: 5222
    ...
    ciphers:
       - "ECDHE+AESGCM ECDHE+AES DHE+AESGCM DHE+AES"

4. Test!

Use your browser, mail client, xmpp client and SSL Labs to test your new configuration. Do not make changes without testing – one typo can break your service.

Review the entire set of test results carefully.

  • You should have nothing in red anywhere outside of the Handshake Simulation
  • You should have Forward Secrecy on every client and browser except on Windows XP

Pay special attention to the Handshake Simulation section, where you can see which browsers will have problems connecting to your site.

5. Going for the SSL Labs’ A+

SSL Labs won’t give you an A+ without Strict Transport Security enabled. You’ll only want to enable this on domains where the entire site is expected to utilize HTTPS and you never want a browser to connect using HTTP.

Apache:

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

Nginx:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";

Bonus points

* Submit your HSTS protected site to the browser preload list: https://hstspreload.appspot.com/

* Enable OCSP Stapling.

* Enable DNS CAA.  You can use SSLMate to generate CAA records for your DNS server/Certificate Authority. If you’re like us and using letsencrypt, the record is simply:

IN CAA          0 issue "letsencrypt.org"