Configuring Apache, Nginx, and OpenSSL for Forward Secrecy

In my earlier blog post, I gave an overview of Forward Secrecy, as well as some configuration tips. If you're new to the concept, I suggest that you go and read that post first. This time, I am following up with detailed configuration examples for Apache, Nginx, and OpenSSL.

Software Requirements

To deploy Forward Secrecy, you need to have both your web server and the underlying SSL/TLS library support Elliptic Curve (EC) cryptography. For Apache, Nginx, and OpenSSL, the following minimum versions will suffice:

OpenSSL 1.0.1c+

Apache 2.4.x+

nginx 1.0.6+ and 1.1.0+

You will probably want to upgrade to the most recent versions wherever possible, because you don't want to be running old and obsolete and potentially vulnerable software. If your distribution does not support an acceptable version of one of the components, consider installing everything from scratch, as I described in a recent blog post.

You are probably aware that Linux distributions often ship modified packages. The modifications are usually improvements, but could mean feature removal in some cases. For example, Red Hat appears to have no support for Elliptic Curve crypto on their operating systems, because of patent issues. If you're running CentOS, for example, and wish to support Forward Secrecy, you will need to recompile the key packages to put EC support back in. (There appear to be plenty tutorials on the Web for this.)

Once the correct packages are in place, enabling Forward Secrecy requires two steps:

Configure the web server to actively select suites Activate the correct OpenSSL suite configuration string

The following configuration advice applies only if you are using compatible software components, as described in the previous section. It is not possible to support Forward Secrecy otherwise.

Apache

To configure Apache, you need to have the following lines in your configuration:

SSLProtocol all -SSLv2 -SSLv3 SSLHonorCipherOrder on SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"

Nginx

To configure Nginx, you need to have the following lines in your configuration:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";

RC4 versus BEAST

Today, only TLS 1.2 with GCM suites offer fully robust security. All other suites suffer from one problem or another (e.g, RC4, Lucky 13, BEAST), but most are difficult to exploit in practice. Because GCM suites are not yet widely supported, most communication today is carried out using one of the slightly flawed cipher suites. It is not possible to do better if you're running a public web site.

The one choice you can make today is whether to prioritize RC4 in most cases. If you do, you will be safe against the BEAST attack, but vulnerable to the RC4 attacks. On the other hand, if you remove RC4, you will be vulnerable against BEAST, but the risk is quite small. Given that both issues are relatively small, the choice isn't clear.

However, the trend is clear. Over time, RC4 attacks are going to get better, and the number of users vulnerable to the BEAST attack is going to get smaller.

Configuring OpenSSL (with RC4)

This configuration assumes you wish to deploy best-possible configuration supporting Forward Secrecy, and that you have a preference for GCM suites (resistant to timing attacks) and RC4 (resistant to BEAST). To achieve best performance, the faster ECDHE suites are used whenever possible.

EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS

To see what suites the above configuration string uses, invoke the following command (all one line):

$ openssl ciphers -V 'EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS'

The output will be similar to this:

ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-RC4-SHA SSLv3 Kx=ECDH Au=RSA Enc=RC4(128) Mac=SHA1 ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 ECDHE-ECDSA-RC4-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=RC4(128) Mac=SHA1 DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(256) Mac=SHA1 DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1 DHE-RSA-SEED-SHA SSLv3 Kx=DH Au=RSA Enc=SEED(128) Mac=SHA1 DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(128) Mac=SHA1 ECDH-RSA-RC4-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128) Mac=SHA1 ECDH-ECDSA-RC4-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128) Mac=SHA1 RC4-SHA SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=SHA1

If you deploy your configuration, your SSL Labs test results might look like this.

Notes:

The list begins with a number of strong TLS 1.2 suites (GCM, SHA256, and SHA384); this helps avoid RC4 whenever possible.

ECDSA suites are preferred to the RSA ones, giving you a performance edge in a dual-certificate deployment scenario.

The main 2 suites (for the current browsers, most of which do not support TLS 1.2) are ECDHE-RSA-RC4-SHA and ECDHE-ECDSA-RC4-SHA , used for RSA and ECDSA certificates, respectively.

and , used for RSA and ECDSA certificates, respectively. The DHE suites are there to support those rare browsers that do not support ECDHE. (Opera before version 15 is one such browser. Firefox as shipped on Red Hat systems another.) These suites are slower, but the majority of browsers will offer the faster ECDHE.

The RC4-SHA suite at the end is there to support IE8 running on Windows XP. (And possibly IE6, but I have not tested for it.)

Internet Explorer, in all versions, does not support the ECDHE and RC4 combination (which has the benefit of supporting Forward Secrecy and being resistant to BEAST). But IE has long patched the BEAST vulnerability and so we shouldn't worry about it.

Same comment as above for Firefox on Red Hat systems.

It is impossible to support Forward Secrecy for IE8 running on Windows XP, because this browser does not support the necessary suites. The same is probably true for any IE version running on Windows XP. If you'd rather not handshake with such browsers, add !RC4-SHA to the configuration.

Configuring OpenSSL (without RC4)

Issues:

If you prefer not to use RC4, use the same configuration string (for simplicity), but add !RC4 to the end:

EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4

Alternatively (in order to support a very wide range of browsers, including the IE versions running on Windows XP), you could deploy with RC4 enabled, but used only as a last resort:

EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS +RC4 RC4

Final Remarks

Finally, consider the following:

There's a vast number of SSL/TLS clients in deployment, each potentially supporting a unique list of cipher suites. It is impossible to guarantee consistent results across such a large user base.

The Handshake Simulation feature of the SSL Labs test is of great help when choosing cipher suite configuration. It supports a wide range of desktop browsers (including older versions). However, do note that the support for mobile devices is not very good at the moment.

Configuring OpenSSL can be tricky. I recommend reading the (free) OpenSSL Cookbook, which describes the configuration in detail.

Update (21 August): I have tweaked the suite configuration string to position SHA256 and SHA384 suites (which are TLS 1.2-only) after GCM suites and before RC4 suites. This helps avoid RC4 whenever possible. (This matters now because Google Chrome 29 has just been released, and, for the first time, we have a desktop browser that supports TLS 1.2 by default). Of course, I assume that you have upgraded your OpenSSL to 1.0.1d or better in order to fix the timing issues with CBC suites (the so-called Lucky 13 attack).