Securing Nginx against SSL/TLS related attacks
Nulab
October 22, 2013
UPDATE: 2014-04-10 openssl version has been updated to openssl-1.0.1g. It is strongly recommended to use openssl-1.0.1g or later to mitigate the Heartbleed vulnerability.
Last August, a new attack leveraging HTTP compression called BREACH was uncovered at Black Hat USA 2013 and some mitigations against it were disclosed alongside. Thereafter, there have been plenty of ongoing discussions among developers to find practical solutions to such attacks.
As service providers, we pay an incredible amount of attention to the security of our services. In this post, I will share our own safeguarding practices against three popular SSL/TLS related attacks namely BEAST, CRIME and BREACH. Since we are using nginx as a frontend proxy to our backend application servers and it handles all SSL/TLS requests, I will focus on nginx configuration in this post.
BEAST
A post by Ivan Ristic on Qualys Community alluded to a recent decline in BEAST threat as a result of client-side improvements. As Ristic pointed out, using RC4 as a solution has now been understood to be potentially more threatening than BEAST itself. While we have been using RC4 to mitigate BEAST attacks, we have recently started to discontinue it in our services progressively. We discovered the importance of reviewing settings periodically, and, understanding the uncertainties of trade-offs we have altered our approach to focus on overall security rather than on single attacks like BEAST. This led us to deploy the following ssl cipher setting below (one line):
ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AES:RSA+3DES:!ADH:!AECDH:!MD5:!DSS;
We use AWS and Amazon Linux as our platform and need to build nginx with openssl together to use elliptic curve based ciphers like ECDH as Amazon Linux’s openssl does not support them (Since Amazon Linux 2014.03, elliptic curve based ciphers are supported on the built-in openssl. The following procedure is not necessary if you are using Amazon Linux 2014.03 or later. See here). The brief setup procedure will look something like this:
Download nginx and openssl sources to your desired location.
wget http://www.openssl.org/source/openssl-1.0.1g.tar.gz wget http://nginx.org/download/nginx-1.4.2.tar.gz tar zxfv openssl-1.0.1g.tar.gz tar zxvf nginx-1.4.2.tar.gz cd nginx-1.4.2
Afterwhich, configure with the following option:
--with-openssl=../openssl-1.0.1g --with-openssl-opt="enable-ec_nistp_64_gcc_128"
Finally, run make and make install.
CRIME
The mitigation of CRIME is to disable TLS/SPDY compression. For nginx, ssl compression has been disabled for all versions of openssl, including the ones prior to 1.0.0 since nginx 1.2.2. (see Changelog). We are currently using the latest version of nginx and are not required to do anything for CRIME mitigation. If you are using an older version of nginx, you might need to consider upgrading to the latest version.
BREACH
As shown at the beginning of this post, BREACH relies on HTTP compression and gzip filter module plays that role in nginx. Turning the filter off would obviously address the issue, but it will be accompanied by a trade-off that is slow performance. Moreover, we would have to expect a huge performance degression without gzip compression. Therefore, we have adopted two mitigation methods together to compressed response:
- Randomizing secrets per request or masking secrets
- Length hiding
The first is applied on the application side. Handling secrets is purely an application matter and nginx does not take care of it. The second, length hiding, is done by nginx. We can certainly do it on the application side as well, but we prefer doing it on nginx as it is easier to update nginx configuration than to modify and deploy application when you need to enable or disable it in running environment. We have developed a nginx module for this purpose and it’s available on github.
This module appends randomly generated HTML comment to the end of HTML response to hide correct length and make it difficult for attackers to guess secret information. The sample of HTML comment is as follows:
<!-- random-length HTML comment: E9pigGJlQjh2gyuwkn1TbRI974ct3ba5bFe7LngZKERr29banTtCizBftbMk0mgRq8N1ltPtxgY -->
To enable this module, add “length_hiding” directive to server, http or location context in your configuration like this:
location /hiding { proxy_pass http://app; length_hiding on; }
Check your setting
To check the strength of your SSL/TLS setting, I would recommend you to run “ssl server test” by Qualys’ SSL Labs. All you will need is to submit your domain name and it will return a detailed report with many perspectives (eg. whether you use safe protocols or not) and a rating on overall safeness. It will also suggest possible solutions if any vulnerabilities are found. Try it for your own domain and get an ‘A’ rating!
We will keep focusing on our service security and share our experiences and knowledge in this blog. Stay tuned!
Disclaimer and acknowledgement
Please note that the suggestions on this blog do NOT guarantee your service security. They are methods and solutions which we have adopted and worked for us thus far. However, these attacks are complicated and wide-ranging, and solutions vary according to your service. If you find any factual problems, please feel free to give your feedback and I will fix it as soon as possible.
Cover image “Keys, USS Bowfin” was taken by Joseph Novak and available at Flickr.