Update: current Nginx (1.10.1) and OpenSSL (1.0.2h) have good defaults. None of this is needed anymore \o/

In a search to ensure forward secrecy on all servers I manage, I needed to figure out a list of ciphers I want to use. There are numerous articles on the web that tells you what to use, but they are either vague about what really to use, or give you a long list of things you don’t know or care about. After quite some reading and experimenting I finally got a grasp of it, and the end result is not as scary as what those articles say.

There is also a tldr at the end for the lazy ;)

Forward Secrecy and Cipher Suites

Forward secrecy means that in the event of a breach, a key stolen from either side cannot be used to decrypt conversations that happened in the past.

A cipher suite is a combination of a key exchange algorithm, an authentication algorithm, an encryption algorithm and a MAC (message authentication code) algorithm.

In order to achieve forward secrecy, the connection needs to be protected by a cipher suite that uses the DH key exchange algorithm, or its faster (but no less secure) variant ECDH.

Meet OpenSSL

man openssl does not tell you how to list all the cipher suites using DH and ECDH. The documentation about ciphers does, to some extent, but for some reason DH is sometimes called DHE and EDH, while ECDH is called ECDHE and ECDH interchangeably. Ironically I didn’t even know that I was looking for DH and ECDH. The blog posts I found imply that I can search using the command openssl ciphers -v <cipher_string>.

[sarcasm] Neat, now I just need to find out what my cipher string is… [\sarcasm]

After spending some time searching around I found the magic word: openssl ciphers -v DH. This shows all cipher suites using DH.

Building the Best Cipher String

A list of cipher suites using DH and ECDH can be retrieved with openssl ciphers -v 'ECDH DH'. Note that I deliberately put ECDH first, because it is faster.

That’s not it yet, because the list contains cipher suites that don’t have authentication. You want to exclude those: openssl ciphers -v 'ECDH DH !aNULL'

It also contains suites that use weak encryption algorithms. Fortunately and conveniently there is a group containing suites using strong encryption algorithm. You need to and it with your list: openssl ciphers -v 'HIGH+ECDH HIGH+DH !aNULL'

Finally, add other suites (that don’t support forward secrecy) so that you can cater for old sucker clients:

openssl ciphers -v 'HIGH+ECDH HIGH+DH HIGH !aNULL'

TLDR

Use this in Nginx:

ssl_ciphers 'HIGH+ECDH HIGH+DH HIGH !aNULL';

This post is written with the help of:

Questions or comments can go to Hacker News :)