SSL Performance Diary #4: Optimizing the TLS Handshake
In our prior SSL Performance Diary post, Optimizing Data Encryption, we mentioned there are 2 areas of TLS that can harbor performance problems:
Encrypting the data. Data sent back and forth between visiting web browsers and your web server must be encrypted and decrypted. If not configured properly, your page load times can become much slower than unencrypted traffic.
Establishing a secure connection. There are several steps that must occur before a browser establishes a secured connection to your website: identities must be confirmed, algorithms must be selected, and keys must be exchanged. This is known as the TLS Handshake and can have a significant impact on your site performance.
This article covers the second item, Establishing a secure connection. For more information on encrypting the data, please refer to SSL Performance Diary #3: Optimizing Data Encryption.
Optimizing the TLS Handshake
The TLS handshake is the process that the browser and server follow to decide how to communicate and create the secured connection. Some of the things that happen during the handshake are:
- Confirming the identity of the server, and possibly the client.
- Telling each other what ciphers, signatures, and other options each party supports, and agreeing on which to use.
- Creating and exchanging keys to be used later during data encryption.
The TLS handshake is shown in this rather technical looking diagram:
Don’t worry. While there are a lot of details in the diagram, the take away is that a full TLS handshake involves 2 round trips between the client and the server. Because of the difference between latency and bandwidth, a faster internet connection doesn't make these round trips any faster. This handshake will typically take between 250 milliseconds to half a second, but it can take longer.
At first, a half second might not sound like a lot of time. The primary performance problem with the TLS handshake is not how long it takes, it is when the handshake happens. Since TLS handshakes are part of creating the secure connection, they have to happen before any data can be exchanged. Look at the waterfall diagram below: (if you need help, check out how to read a webpage waterfall chart.)
The TLS handshake, shown in purple, is adding 750 ms of delay to the time it takes to get the initial HTML page. In this example, getting the HTML page over TLS takes twice as long as getting the same page over an unencrypted connection! Worse, the browser can't do anything else until it gets this initial HTML page. It cannot be downloading other resources in parallel, like CSS files or images, because it hasn't gotten that initial HTML page telling them about the other resources. This is true with every webpage you visit: the browser is blocked getting that first HTML response. Unfortunately, the TLS handshake increases the amount of time where the browser can't do anything, slowing down your site performance.
Also, remember the TLS handshakes happen at the start of every new HTTP connection. Since browsers download resources in parallel, this means that a visiting browser will create multiple TLS connections and have to wait for multiple handshakes to complete, even with visiting a single page!
Unfortunately, there is not a lot of extra or unnecessary data that we can optimize during the TLS handshake. The primary aspect we can optimize is the "confirming the identity of the server" step. To do this, the browser looks at something called the certificate chain.
The Certificate Chain
Keeping a short certificate chain is critical to keeping your HTTPS site performing fast. So much so, that we already devoted a full post on this topic! For more information, check out our SSL Performance Diary #1: The Certificate Chain.
Avoiding Full TLS Handshakes
At its heart, the TLS handshake is about the client and the server verifying each other, agreeing on a common set of ciphers and security options, and then continuing the conversation using those options. It seems silly that a client and a server that have recently communicated before need to go through this full process over and over again. Imagine this scenario: You are visiting a blog like this one over TLS. Multiple TLS connections with multiple handshakes were made to download all the content. In a few minutes, you click a link to read a different page on this site, which causes your browser to do multiple TLS handshakes all over again.
This is where TLS session resumption comes in. Basically, TLS session resumption allows a client to say, "Hey server, we communicated a little while ago and did so using the following TLS options… Is it OK to start talking again using those same options?" This is a huge improvement on performance. A full TLS handshake requires 2 round trips to create the secure connection. TLS session resumptions allows us to do it with 1 round trip.
The great thing about session resumption is that it is basically a free short-cut. When the client asks the server, "can we use these previously agreed upon settings?", it does so as part of the first round trip in setting up a full TLS handshake. If the server agrees, great, the short cut is followed and no further handshaking is necessary. If, for whatever reason, the server doesn't agree to the session resumption request, the TLS handshake continues as normal and completes in 2 round trips. There's no reason not to use session resumption.
There are 2 different mechanisms to implement TLS resumption. The first is Session Identifiers and the second is Session Tickets. They both do the same thing. The difference between them is primarily which side has to keep track of the previously agreed upon options. All web browsers support both, but some web servers, like Microsoft's IIS, only support session identifiers. Session identifiers are a slightly older mechanism, and can potentially expose your to Denial of Service attacks. Enabling either session identifiers or sessions tickets is done via your web server configuration, and is quite easy. Consult with your administrator about getting these options enabled.
- Enabled TLS resumption on your web servers.
- If possible, avoid using session identifiers to reduce your exposure to Denial of Service attacks.
Other TLS Options
There are several other TLS options and nuances we are glossing over: What asymmetric algorithm you should use? What key exchange protocol should you use? What key size should you use for your symmetric cipher? Should you be using perfect forwards secrecy? These are important decisions from a security perspective, and everyone's needs are different. From a performance perspective, these are largely moot. It is best to leave these choices to whoever manages your server, or to follow advice from Mozilla.
Minimizing TLS Handshakes Altogether
As we have seen, the TLS handshakes, while necessary, can have an impact on your performance:
- They can delay the download of critical responses like the initial HTML page.
- They can happen multiple times on a single page.
- There isn't much we can do to optimize them.
While session resumption can cut the delay of a TLS handshake in half it is still best to avoid TLS handshakes altogether. You can do this by minimizing how many HTTP connections a browser makes when visiting your website. Luckily, many traditional front-end performance optimizations that you should be doing anyway can help. This makes front-end performance optimizations even more important on sites secured with TLS. Let’s focus on 4 optimizations that are particularly relevant for sites using TLS.
Persistent connections allow HTTP to make multiple requests over a single HTTP connection. Persistent connections allow the browser to load the page faster because it can make requests more quickly. But it can also cut down on the number of TLS handshakes. Consider this waterfall, which we looked at before:
See how virtually every HTTP request has a purple section? This purple section is the TLS handshake. Why does it keep happening? Because the web server is explicitly closing the HTTP connection, and thus the underlying TLS connection, with every response. We can see this with the
Connection: close response header, as shown below:
This is terrible for performance in general, but especially bad for a site using TLS. Your website should be using persistent connections.
Domain sharding is a technique to trick a visiting browser into downloading resources from your website more quickly. It works by having a single web server with different hostnames. For example, your site might be named
example.com, but configured to resolve the names
static2.example.com to the same server. Since browsers allow only a limited number of HTTP connections to a single hostname at the same time, using multiple hostnames trick the browser into downloading more content in parallel.
The problem with domain sharding is that the browser doesn't know that
static2.example.com are all the same server. It will make new HTTP connections to each hostname, and have to do a full TLS handshake each time. In our example, we are potentially doing 3 times the number of TLS handshakes because of our sharded hostnames. Additionally, session resumption information for connections on one hostname cannot be used by connections to another hostname, even though under the covers all these names refer to the same server.
The net result is that increased number of TLS handshakes caused by domain sharding may offset any advantage gained from downloading more content in parallel. In fact, sharding a TLS protected website might actually make it slower. This is especially true if you follow the next two pieces of advice, which will reduce the number of items that need to be requested at all.
The fastest request is one the browser doesn't have to make. Caching might be the best front-end performance optimization you can make. If I just visited your site, and I'm looking at a second page, there is no reason to download your logo a second time. If you don't use caching, the browser must check with your website if it is OK to use logo image it has previously downloaded. This is called a conditional request, and it's bad for performance. Because of the difference between bandwidth and latency, even if you don't actually download anything from the server, simple sending a request to ask if it is OK to use a logo takes almost as long as just downloading the logo again.
- Enable persistent connections. Ensure your application or CMS is not prematurely closing HTTP connections.
- Use tools like WebPageTest to see if domain sharding will actually improve performance for your TLS enabled website.
- Combine multiple JavaScrpt and CSS files into bundles where appropriate.
- Cache your static resources for 5 minutes, even if you don't have a file versioning system in place.
- If you have the infrastructure and processes in place, use far-future caching with a file versioning system that changes the URLs of your resources when they change.
- Test your site to ensure you are properly implementing front-end performance optimizations.
Google is now favoring websites that are secured using TLS in search engine rankings. TLS can have an impact on performance and this article has shown you the steps you can take to minimize the impact.
The data encryption overhead for secure connections is largely a problem of the past, thanks to faster CPUs with built-in support for AES cipher operations. The TLS handshake can be optimized by keeping your certificate chain short by purchasing your certificate from a large, well known vendor whose signing certificates on the trusted list instead of web browser. You can speed up subsequent TLS handshakes by enabling session resumption on your server. You can avoid many TLS handshakes all together by implementing common front-end performance optimizations like persistent connections and caching, and avoiding tricks like domain sharding. You can also use Zoompf’s free performance report to ensure your website is using AES and is properly implementing the suggested front-end performance optimizations.If you’d like to stay on top of your website performance, consider joining the free Zoompf Alerts beta to automatically scan your website every day for the common causes of slow website performance.