Transport Layer Security (TLS) is a cryptographic protocol that enables secure communications over a computer network. It has been in widespread use on the Internet for various services, such as e-commerce, web browsing, and instant messaging.
TLS has also been made effectively mandatory in HTTP/2, the latest revision of the HTTP network protocol. It is estimated that as of October 2017, 18.1% of the top 10 million websites supported HTTP/2.
Given TLS’s current use and certain future growth, it has been of critical importance to us that TLS sessions in HAProxy are established as fast as possible.
TLS Session Establishment
By specification, not taking the TCP connection initialization into account, TLS sessions are established using a 2-RTT handshake. This means there are two exchanges (round trips) of data between the client and the server that need to take place before the client can send its actual request. This may affect user experience, especially in mobile networks or network conditions that include higher packet loss or high latencies.
To partially solve the problem, the TLS specification already allowed TLS sessions to be resumed. Specifically, once the client has connected to the server for the first time, on subsequent connections it can send a session ID. If the ID is known and accepted, the TLS keys will not be exchanged (one round trip will be saved) and the session will be established in 1-RTT.
The upcoming TLS 1.3 specification goes even further in resolving the problem – it enables sessions to be established in 0-RTT! Namely, existing sessions are resumed with a standard 1-RTT, but the specification allows the clients to include the actual data (called “early data”) as part of the handshake, thus achieving 0-RTT.
The potential performance improvements are significant. If the server is fast in serving requests, its response to a request containing early data (0-RTT) could arrive to the client faster than it would take a standard, new TLS session (2-RTT) to even be established!
While 0-RTT produces excellent results, it contains a security risk — is vulnerable to replay attacks. An attacker could simply record and replay the encrypted early (0-RTT) requests, succeeding in executing them multiple times.
This is serious because it works even when the attacker does not have knowledge of the TLS keys or any other information that would allow him to complete the TLS handshake and execute the requests in a normal way.
Also, lacking the correct TLS keys, the attacker would not be able to read the responses from the server, but the actions would be executed nevertheless. You certainly wouldn’t want POST HTTP requests that trigger financial transactions to be executed multiple times outside of your awareness or control, regardless of whether the attacker would get to read the responses or not.
So, special care has to be taken when dealing with 0-RTT and early data contained in the handshake packets. One should only allow “safe” requests to be executed in 0-RTT (with the definition of safe depending on the application). However, a web page is usually composed of a large number of objects, many of which are safe to get using 0-RTT, so even with the security considerations in mind, using 0-RTT can be a huge win!
0-RTT in HAProxy
In the upcoming stable release of HAProxy 1.8, we have implemented full support for 0-RTT, including the industry-first implementation of the 0-RTT security risk solution described in the httpbis Working Group draft “Using Early Data in HTTP“.
HAProxy 1.8 is currently available as HAProxy 1.8 Release Candidate 3 (RC3), and to enable 0-RTT, it needs to be compiled with the upcoming stable release of OpenSSL 1.1.1.
Once HAProxy version 1.8 is compiled with OpenSSL 1.1.1, 0-RTT can be enabled by adding “allow-0rtt” to the “bind” or “server” lines.
HAProxy will use 0-RTT to connect to the backend servers when the client has used it. If the client’s request is 0-RTT (i.e. it contains early data), then HAProxy will set the corresponding HTTP request header “Early-Data: 1”.
Backend servers can decide which requests can or cannot be served using 0-RTT. If a request is not allowed to contain early data and is to be rejected, this can be done by returning response code HTTP 425 (Too Early).
If the backend server rejects early data, HAProxy will not be able to re-send it as normal data, and it will forward the HTTP 425 (Too Early) response to the client, asking it to repeat its request without early data.
New Sample Fetches
A new sample fetch has also been added, named “sslfchas_early”. This will be true when a client sends early data.
A new action has also been added, named “wait-for-handshake”. When used, HAProxy will wait for the handshake to be completed before handling the request. (As we have explained above, once the handshake is completed, we can be sure that the described 0-RTT security risk is no longer present.)
We hope you have enjoyed this blog post describing the use of 0-RTT functionality in HAProxy and its industry-first implementation of the draft “Using Early Data in HTTP“.
HAProxy’s full-featured 0-RTT support gives you full freedom of choice in deciding how to handle sensitive requests that should not be accessible using 0-RTT. You can:
Use the sample fetch “sslfchas_early” to detect requests with early data and respond with HTTP 425 (Too Early), asking the clients to repeat requests without early data
Pass the requests to the backend servers, letting the backend servers perform a more detailed decision in combination with the HTTP request header “Early-Data”
Use the action “wait-for-handshake” to delay processing the requests in HAProxy until the handshakes are completed and security risks no longer present
If you would like to make use of some of the new features before waiting for the stable release of HAProxy 1.8, please see our HAProxy Enterprise – Trial Version or contact HAProxy Technologies for expert advice.
Stay tuned and happy 0-RTT! 🙂