It comes at no surprise that a lot of people are looking into moving their sites to HTTPs due to recent events: Google’s decision to give ranking points to sites that use SSL / HTTPs and eavesdropping by governments world wide. There are a number of considerations before taking this step, specially for people who have not yet deployed HTTPs / SSL on their web servers.
There are a number of things you need to start doing and fixing in order to have a functional site that performs well. Because most sites were not thought to use SSL to begin with, you’ll find that there might be problems when accessing your site from https instead of http. Below are a few tips to consider although it is not an exhaustive list:
- Internal links: If you are using WordPress you will find a lot of the links you have not only do they include http:// but also the domain name. This is a problem for two reasons: 1) you are hard coding the transport (in this case http) so even if you use a different transport it will force the browser to take the hard coded one and 2) You are hard coding your site’s URL. Imagine you change your domain name… now you have to change all your URLs. For these reasons I generally recommend people use relative URLs (they start with / vs the transport or domain name).
- Infrastructure concerns: Make sure your CDN supports SSL as well as any other part of your infrastructure (reverse proxies, firewalls, etc). Consider using SPDY when using SSL for added performance benefits. I really like using http://spdycheck.org/ to check for SPDY readiness. It lets you know if you have deployed SPDY and other tips to get the most out of it. We will go over the checklist for this in a minute
- NginX specific configuration: We will cover the required configuration needed to address the implementation of an SSL site as well as performance considerations.
So let’s get to it!
I. Use SSL cache
As you can imagine hosting a site using SSL requires additional work on the CPU. We need to make sure we don’t saturate the CPU otherwise our site will be loading much slower. For example, I once tried using a 16k bit certificate… my CPU would die depending on the number of requests it had to handle. For that reason I’ve joined the 99% of people in using a 2k bit certificate for my site. For that same reason we need to turn on SSL session cache on NginX to save on CPU resources:
II. Use the right cyphers
This was also a surprise to me, but you can configure the cyphers NginX uses. This has two major impacts: 1) Certain cyphers are weak or vulnerabilities have been discovered. Pretty much using them does not guarantee much security or worse case, compromises the security of your entire site. 2) Certain cyphers are more CPU intensive than others. Surely you want to be helpful for the poor guy who uses that strange CPU intensive cypher but you’re just asking for trouble down the road. I wrote an article on CloudFlare recommended configuration here: How to: Improve SSL performance on NginX which you can also refer to as well as this article: Hardening Your Web Server’s SSL Ciphers.
Below is the recommended configuration as of the date of publishing of this post:
III. SPDY readiness
So now we are ready to use SPDY! We’ll go step by step through some recommended configurations:
a) Enable SSL with SPDY on the default port 443
listen 443 spdy ssl;
b) Use a valid X.509 Certificate
As long as you are using a valid certificate from a public key certificate authority you’re more likely than not fine.
c) Server Hello Contains NPN Extension
If you are using NginX you’re probably fine. Make sure you are running the latest version.
d) Enable HTTP Fallback
All this means is that your site is also available via HTTP just in case
listen 80 default_server;
listen 443 default_server spdy ssl;
e)HTTP Redirects to HTTPs / SSL / SPDY
If a visitor arrives via HTTP, have your webserver redirect them to the HTTPs version of your site. If you have SPDY enabled they will probably have a faster loading experience.
listen 80 default_server;
server_name cloudingenium.com *.cloudingenium.com;
return 301 https://$host$request_uri;
f) Use HTTP Strict Transport Security (HSTS)
All this does is indicate your client that for future requests for your site it should use SSL. I set up the max age to one day as I am starting to test site wide SSL deployment. If you feel very comfortable with this I have observed most people use a max age of one year. Be as it may the important thing is to enable it and like cache use a reasonable time in case you are forced to go back to a non-SSL site.
# This forces every request after this one to be over HTTPS for one day
add_header Strict-Transport-Security “max-age=86400; includeSubdomains”;
Don’t forget that the includeSubdomains should only be used if you are deploying Strict Transport Security to your subdomains as well. You can remove it if you don’t want your subdomains to use HSTS.
UPDATE: SSLLabs recommends using at least 180 days for your HSTS. So you should use 15552000 for max age once your done testing and find the performance of your site acceptable.
g) Enable OCSP Stapling
If you are not sure what OCSP Stapling is, I recommend reading the CloudFlare article: OCSP Stapling: How CloudFlare Just Made SSL 30% Faster. Pretty much what this does is remove a large portion of the SSL overhead by doing some work on your server. This is good as your visitors will enjoy a faster experience on your site.
First you need to make sure your certificate includes the entire certificate chain. I’ll look up a previous post I had on how to concatenate certificates to achieve this (pretty much you have your certificate and attach to it the certificates of each public certification authority above it.)
Here is the code needed on NginX:
ssl_stapling on;ssl_stapling_verify on;resolver 18.104.22.168 22.214.171.124 valid=300s;resolver_timeout 10s;
Do keep in mind we are using Google’s resolvers for this. You can use other DNS resolvers if you prefer.
Here is a sample report from SPDYCheck.org:
Strict-Transport-Security: max-age=86400; includeSubdomainswhich tells the web browser to always use SSL to access this website for the next 1 days.
Improve SSL performance on NginX
You would be surprised but a lot of people face SSL performance issues when using NginX. I recently deployed SPDY over SSL for my sites and came to realize that SPDY was in fact much slower than using standard HTTP. I proceeded to leave SSL alone and see its performance vs regular HTTP and again the speed was equally slow. Because of that I realized that SPDY was not the issue but rather the SSL layer. There are certain algorithms or cyphers that require a lot of processing (cpu power) which results on your SSL configurations being slow. Coming from Windows I never really messed with that or realized you could, but after using NginX you come to realize the wide range of things you can control but really getting to know them all requires a lot of specialized knowledge the amateur user might not have. Also while researching this topic I came across security advisories like these ones on CloudFlare; Staying on top of TLS attacks and Taming BEAST: Faster, Safer SSL now on CloudFlare.The list keeps going on and on, and not surprisingly the recommendations keep changing with time. So as SSL gets more use things like performance and security start getting more attention and start receiving improvements.
So getting back on topic, there are a number of things you can do to speed SSL like OCSP Stapling but also disable certain ciphers because they are simply terribly slow. For example, NginX uses the DHE algorithm to create the cypher. This algorithm is really slow with NginX. Disabling it results in dramatic improvements (at least it did for me and reading online it is mentioned a lot.)
Long story short, there are a few recommendations (obviously with time you learn you can’t get it 100% right.):
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m;
So here is what’s going on:
Obviously you want to use the latest version of TLS but that is not supported by all browsers so we offer versions 1, 1.1 and 1.2.
Here is an improved list of which SSL ciphers you should support.
The next line indicates that you should indicate the client that it prefer it uses the ciphers specified by the server.
The next line allows to cache the ssl sessions. This is a very important improvement as having to re-create an SSL session in an expensive operation.
The final line indicates the timeout for an SSL session.