Tweaking HTTPS for Better Security


The HTTPS protocol is based on TLS and SSL, which are standard ways to negotiate encrypted connections. There is a lot of complexity in the protocols and lots of config options, but luckily most of the config options can be ignored since the defaults are fine. But there are some things worth tweaking to ensure that as many connections as possible are using reliable encryption ciphers while providing forward secrecy. A connection with forward secrecy provides protection to past transactions even if the server’s HTTPS private key/certificate is stolen or compromised. This protects your users from large scale network observers that can store all traffic for later decryption, like governments, ISPs, telecoms, etc. From the server operator’s point of view, it means less risk of leaking users’ data, since even if the server is compromised, past network traffic will probably not be able to be encrypted.

In my situation, I was using our development site, https://dev.guardianproject.info, as my test bed, it is Apache 2.2 and openssl 1.0.1 running on Ubuntu/precise 12.04 Long-Term Support, so that means that some of the options are more limited since this is an older release. On Debian, Ubuntu and other Debian-derivatives, you’ll only need to edit /etc/apache2/mods-available/ssl.conf. There are more paranoid resources for perfectly configuring your TLS, but we’re not ready to drop support for old browsers that only support SSLv3, and not TLS at all. So I went with this line to enable SSLv3 and TLSv1.0 and newer:
<br /> SSLProtocol all -SSLv2<br />

With TLS connections, the client and the server each present a list of encryption ciphers that represent the ciphers they each support in order of preference. This enables the client and server to choose a cipher that both support. Normally, the client’s list takes precedence over the server’s, but with many browsers that can be changed. Unfortunately it seems that Microsoft Internet Explorer (IE) ignores this and always uses the client’s preference first. Here’s how to make Apache request that the server preferences are preferred:
<br /> SSLHonorCipherOrder on<br />

Next up is tweaking the server’s preference list to put ciphers that enable forward secrecy first (don’t worry if you don’t understand the next stuff about my rationale, my aim is to walk thru the process). This is done in most web servers using openssl-style cipher lists. I started out with what Mozilla recommends, then pared down the list to remove AES-256 ciphers, since AES-128 is widely regarded to be faster, quite strong, and perhaps more resistant to timing attacks than AES-256. I also chose to remove RC4-based ciphers, since RC4 might already be broken, and will only get worse with time. RC4 has historically been used to mitigate the “BEAST” attack, but that is mostly happening in the clients now. So with that I ended up with this cipher list (should be all one line in your config file):
<br /> SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-CAMELLIA128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:CAMELLIA128-SHA:DES-CBC3-SHA"<br />

One thing to make sure is that all of these ciphers are supported on your system. You can get the list of supported ciphers from openssl ciphers. I used this command line to get them in a nice, alphabetized list:
<br /> openssl ciphers | sed 's,:,\n,g' | sort<br />

Lastly, we want to set the HSTS header to tell the browser to always use HTTPS. To enforce this, a header is added to the collection of HTTP headers delivered when connecting to the HTTPS site. This header tells the client browser to always connect to the current domain using HTTPS. It includes an expiration date (aka max-age) after which, the client browser will again allow HTTP connections to that domain. The server might then again redirect the HTTP connection to HTTPS, and again the client will get the HSTS header, and use only HTTPS until the expiration date comes again. To include this header in your Apache server, add this line:
<br /> Header add Strict-Transport-Security "max-age=15768000;includeSubDomains"<br />

Now you can check the results of your work with Qualys’ handy SSL Test. You can see the result of my efforts here: https://www.ssllabs.com/ssltest/analyze.html?d=dev.guardianproject.info. A- is not bad. I tried for a good long while to get IE to use FS (Forward Secrecy) ciphers, but failed. IE does not respect the server-side cipher preferences. My guess is that the only way to get IE to use FS ciphers is to make a custom cipher list that does not include anything but FS ciphers and serve that only to IE. I know it is possible to do because bitbucket.com got an A+ for doing it. For a quick way to check out the cipher lists and HSTS header, look at iSEC Partner’s sslyze.

This is only a quick overview of the process to outline the general concepts. To find out more I recommend reading the source articles for this post, including specific directions for nginx and lighttpd: