Perfect Forward Secrecy (PFS) is a concept in Transport Layer Security (TLS) that makes sure that even if attackers manage to gain access to the private key of a certificate, they are not able to decrypt communication from the past (or communication in the future, without using active man in the middle attacks). Or in other words: An attacker (e.g. a state level actor) can usually record encrypted communication of users with a website which is protected by TLS. Let’s assume that after some months of recording the encrypted data, the adversary then also manages to steal the private key from the website’s server (8). Without PFS, it is possible to decrypt all TLS connections that was previously recorded, and also all future communication (until the certificate and its private key are renewed).
With PFS enabled on the communication, the attacker should be not able to do so, and is therefore thwarted. This is implemented in TLS by using the private/public key of the server’s certificate only to authenticate the server. The encryption key is exchanged separately, for example via the Diffie-Hellman (DH) key exchange protocol. Therefore each TLS connection exchanges its own ephemeral and unrecoverable session key (independent of the used server certificate), and a stolen private key is of no help to an adversary trying to decrypting the communication.
Even with this useful feature, there are however also performance enhancements in the TLS standard which can weaken this PFS implementation. These performance enhancements are needed to lessen the burden of performing expensive mathematical operations on the web server to create new cryptographic keys (1). To reduce the amount of cryptographic operations during the process of establishing a TLS connection, the already existing, old cryptographic key material can be re-used.
There are two main standards which allow this:
- Session IDs (server and client both store the secret state, and associate it with an ID)
- Session Tickets (the server sends the secret state to the client, encrypted)
We will have a look how this session resumption standard works, and how this weakens PFS.
When using session IDs, the cryptographic parameters are stored on the server and associated with an unique random ID, which is sent to the client. It can be loosely compared with session cookies in web applications. If the client initiates a new connection to the server, the associated Session ID is transmitted. The server can then access the stored parameters, and both the server and the client are able to re-use the previously negotiated keys. Note that the client will just remember his own key material, and re-use it upon session resumption.
In a load balancer scenario, all servers need to share the session storage (consisting of session IDs and cryptographic parameters). If this is not the case, then if a client gets load balanced to a server which does not have (e.g. did not create) the cryptographic parameters, the client and server are not able to perform session resumption as the keys which are required for it are not available on the server side.
When using session tickets, the server encrypts the cryptographic parameters, and sends it as a “blob” (predictably called “session ticket”) to the client. It can be loosely compared with the ViewState in web applications. The client is not able to decrypt or modify this blob. If the client initiates a new connection to the server, he also sends this blob back to the server. The server is able to verify and decrypt the blob, and again has all the needed information to continue performing encrypted communication with the client, without the need to exchange new keys. Here too the cryptographic parameters of the client are managed by the client, and re-used for session resumption (independent of the blob).
In a load balancer scenario, all servers need to share the key used to encrypt and decrypt the Session Ticket.
Attentive readers probably already identified some security related issues when reading the session resumption concept and the load balancing specifics. To benefit from PFS, we need to ensure that the used TLS related cryptographic material is not stored. However, session resumption relies on the cryptographic material to be stored at least temporarily in some way. If we still want to profit from both of these concepts we therefore always end up with a trade-off.
When using Session IDs, it is necessary to only keep the session ID data for a short amount of time. An attacker which compromises the web server is able to dump the Session ID store, and with the obtained secrets to decrypt previously recorded communications. In the case of Session Tickets, the session-ticket encryption key is the weak point, as it could be stolen and used to decrypt the session ticket (blob) sent by the server (or by the client on session resumption). With the information within the session ticket an adversary can easily decrypt the actual communication between client and server (their DH exchanged secret keys).
Also note that Session Tickets are always encrypted with AES-128-CBC and integrity protected using HMAC-SHA-256. Even if you use stronger algorithms for your TLS connections, let’s say AES-256-GCM, when using Session Tickets the security ends up being reduced to 128 bit AES.
Therefore, if PFS is a strong requirement, you have to ensure that the lifetime of Session IDs are not too long. In addition, one should also change the key for Session Tickets periodically. If both are only valid for 24 hours, the attacker can only decrypt a maximum of 24 hours of network communication. For example, Twitter rotates their Session Ticket encryption key every 12 hours, Cloudflare even every hour. Additionally, it is important to not store the keys or session cache on hard disks, but only in memory, as they may be recoverable from the hard disks via forensic analysis otherwise.
If your web servers have enough power you might actually consider disabling Session IDs and Session Tickets altogether. This is still the recommended solution, as most used web servers (Apache, Nginx) do not support Session Ticket key rotation.
In the upcoming TLS 1.3 standard, session resumption has been reworked. There are two new mechanisms for session resumption, psk_ke and psk_dhe_ke. psk_ke provides the same implementation and therefore security as the session resumption in the current TLS standards (up to TLS version 1.2). psk_dhe_ke is making it more secure by incorporating an additional shared (EC)DHE key (PSK) into the derived master secret upon first connection. This PSK gets a unique ID, and can be re-used in further connections. See (1) for more details. Therefore, an attacker is not able to decrypt PFS traffic with Session Resumption support, even when gaining access to Session ID data or the Session Ticket encryption key.
What is described here is also applicable for PFS enabled VPN solutions. Both OpenVPN and IPSec are able to perform PFS. For key rotation, consult your documentation or vendor.
Web Server Support
Here follows some examples of key rotation support in common web server implementations.
- Caddy support TLS ticket key rotation; https://github.com/wmark/caddy/commit/29235390dca843cb50a10bc104565cbeef981586
- Apache Traffic Server supports ticket key rotation: https://docs.trafficserver.apache.org/en/5.3.x/admin/security-options.en.html#rotating-tls-session-ticket-keys
- Apache Web Server does not support Session Ticket key rotation. It has to be restarted to generate a new Session Ticket key: http://httpd.apache.org/docs/trunk/mod/mod_ssl.xml#sslsessiontickets
- IIS support configuring Session ID expiry: https://technet.microsoft.com/en-us/library/dn786418(v=ws.11).aspx#BKMK_SchannelTR_ClientCacheTime
- IIS does support Session Ticket keys, but key rotation support is unclear: https://technet.microsoft.com/en-us/itpro/powershell/windows/tls/new-tlssessionticketkey
- Nginx does not support Session Ticket key rotation (out of the box): http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_session_tickets
Thanks to Cyrill Bannwart for technical review, and Carel van Rooyen for general review of this text.
- Actually, its “new cryptographic material”. What is generated is the “master secret” and the used ciphers. The actual keys used for encryption are generated by expansion: PRF(master_secret, key expansion, server random, client random). TLS session resumption makes it obsolete to perform the key exchange via DH/RSA, and the calculation of the master_secret (but the key expansion has still to be performed). We simplified the description in this blog article to make it easier to understand.
- Note that stealing the private key is not the only option. It will be possible in the future to crack the private key, be it with brute force or cryptoanalysis.