Exciting things have been happening on TLS land lately. TLS 1.3 was finally released, bringing many security and performance improvements. It would be awesome if everyone switched to TLS 1.3 right now, but that seems hardly realistic as many libraries and applications are still lacking TLS 1.3 support.

That said, it is possible to have a fairly robust TLS setup using currently available versions, provided care is taken. In this article, we propose just that: how to create a modern and secure TLS setup, while maintaining an adequate level of compatibility. Additionally, we provide ready-to-use Terraform examples for a Docker-based nginx reverse proxy setup, with TLS 1.3 support, and Let’s Encrypt automatic certificate renewal, for both Amazon Web Services and Google Cloud Platform. This setup allows you to quickly enable TLS on any web application.

TL;DR;

If you are impatient, you can jump directly to the recommendations and examples.

An impatient Storm Trooper. Photo by John Moeses Bauan.

A brief TLS timeline

In the beginning, there was SSL 1.0 . Not much public information is available. According to one source, several design flaws, such as missing data integrity and no replay protection, prevented SSL 1.0 from seeing the light of day;

. Not much public information is available. According to one source, several design flaws, such as missing data integrity and no replay protection, prevented SSL 1.0 from seeing the light of day; SSL 2.0 , the first public version, is eventually released in March 1995, as part of Netscape Navigator 1.1 browser. Several security issues are found, such as cipher downgrade and length-extension attacks;

, the first public version, is eventually released in March 1995, as part of Netscape Navigator 1.1 browser. Several security issues are found, such as cipher downgrade and length-extension attacks; SSL 3.0 is released in March 1996, with Netscape Navigator 2, fixing several vulnerabilities found in SSL 2.0;

is released in March 1996, with Netscape Navigator 2, fixing several vulnerabilities found in SSL 2.0; TLS 1.0 , a.k.a. SSL 3.1, is released in January 1999, after a standardization effort by the IETF. It is an incremental evolution over SSL 3.0, bringing no dramatic changes;

, a.k.a. SSL 3.1, is released in January 1999, after a standardization effort by the IETF. It is an incremental evolution over SSL 3.0, bringing no dramatic changes; TLS 1.1 is released in April 2006. It includes mitigations to attacks on CBC ciphers. One particular change, explicit initialization vectors, will eventually prevent BEAST, five years into the future;

is released in April 2006. It includes mitigations to attacks on CBC ciphers. One particular change, explicit initialization vectors, will eventually prevent BEAST, five years into the future; TLS 1.2 is released in August 2008. Changes include support for authenticated encryption with associated data (AEAD) ciphers, like AES-GCM, and stricter protocol validations;

is released in August 2008. Changes include support for authenticated encryption with associated data (AEAD) ciphers, like AES-GCM, and stricter protocol validations; TLS 1.3 is released in August 2018. There are many major differences from TLS 1.2, to the point that some believe it should be called TLS 2.0. We will briefly cover them below.

What is TLS?

TLS is a protocol that provides a way for two parties to establish a secure communication channel between them.

That’s it.

But keep in mind that achieving this is no small feat. Look at TLS’ vulnerability history to see how hard it is.

TLS makes establishing a secure communication channel possible by providing three key services:

Confidentiality: ensures that data exchanged between peers is kept secret from third-parties. This is especially important for sensitive data, like passwords, credit cards, and the embarrassing contents of our shopping carts. Confidentiality is the characteristic that is most commonly associated with TLS, and its purpose is usually well understood;

ensures that data exchanged between peers is kept secret from third-parties. This is especially important for sensitive data, like passwords, credit cards, and the embarrassing contents of our shopping carts. Confidentiality is the characteristic that is most commonly associated with TLS, and its purpose is usually well understood; Integrity: makes sure that data transmitted between peers is reliable and not tampered with during transit. Note that in the context of TLS, “integrity” refers to message authentication;

makes sure that data transmitted between peers is reliable and not tampered with during transit. Note that in the context of TLS, “integrity” refers to message authentication; Authentication: ensures that clients communicate with legitimate servers. This is fundamental for assuring both confidentiality, and integrity, by providing trustworthy keying material for encryption and message authentication. Note that authentication and integrity are always important, whether the transmitted data is confidential or not. Optionally, TLS can also be used to authenticate clients, e.g. through client certificates, but this is less common;

Why do we need TLS?

One common criticism against TLS is that “TLS is slow”; for the vast majority of use cases, it is a misconception, even more so in TLS 1.3.

Another argument is that “All information on my website is public, so I do not need TLS”. A service providing public information may not require confidentiality, but authentication and integrity should never be optional. Otherwise, a user visiting an unprotected website has no guarantees about the authenticity of the information contained on it. The user may be attacked or, at best, annoyed by a potential man-in-the-middle — think Wi-Fi networks, or less ethical ISPs.

Some possible attack scenarios follow.

Subtly change a small, but critical, piece of information on a website. Such as a bank account number, cryptocurrency wallet address, phone number, email, and others;

Launch an “opportunistic cryptojacking” attack by injecting cryptocurrency mining code on the original webpage;

Redirect the victim to a phishing page to steal their credentials;

Inject ads and analytics/tracking javascript.

The list goes on.

We believe that it is a matter of responsibility towards users to ensure that communications are properly secured. Regardless of the information being confidential or not. We should be certain that our users are talking with us, and that the message we want to send them is not tampered with by a third party.

TLS 1.3: so hot right now

Photo by Terry Robinson.

TLS 1.3 is the new hotness and we are thrilled about it. Do not let the minor-only version increase fool you: this version is a significant departure from earlier TLS versions. It incorporates many lessons learned since the release of TLS 1.2, ten years ago. It aims to be both faster and safer.

Some highlights are:

Perfect-forward secrecy is now mandatory. From a security and privacy perspective, it is a very good thing. However, this raised some concerns from organizations who rely on passive TLS decryption for security, which TLS 1.3 breaks. This made some people very angry who regarded it as a bad move;

From TLS 1.0 to TLS 1.2, the handshake stayed mostly the same. Not anymore: TLS 1.3 comes with a redesigned, safer and faster 1-RTT handshake. In TLS 1.3, after the initial handshake messages, everything is encrypted. This means that even server certificates are encrypted. Eventually, combined with Encrypted SNI and DNS over HTTPS, an outside observer will not be able to determine which site a user visits (aside from the IP address, of course). Paired with a CDN, this feature may prove crucial for people who need to circumvent Internet censorship;

A ton of stuff was removed: renegotiation, compression, and many legacy algorithms: DSA, RC4, SHA1, MD5, CBC MAC-then-Encrypt ciphers — hopefully fixing CBC padding-oracles once and for all, and more;

Much improved resiliency against downgrade attacks;

Modern Daniel J. Bernstein algorithms are supported by default: x25519, Ed25519, and ChaCha20-Poly1305, which is great;

Session resumption and protocol extensions are significantly different. Session resumption using old-style “session IDs” and “session tickets” are gone. They have been replaced with a unified mechanism based on pre-shared keys (PSK).

If you wish to dig deeper, Cloudflare has done a great job clarifying the new protocol features on their blog here and here.

If you really want to go down the rabbit hole, take a look at the RFC, and this amazing TLS 1.3 byte-by-byte guide, created by Michael Driscoll.

Recommendations guidelines

In order to decide what configuration we should recommend, we take into account four different aspects:

Security — the recommendations should only include settings that are safe against known attacks;

— the recommendations should only include settings that are safe against known attacks; Performance — without sacrificing security, higher-performance options should be preferred over lower-performance alternatives;

— without sacrificing security, higher-performance options should be preferred over lower-performance alternatives; Compliance — if a major standard recommends against specific versions or setup, we will comply with it so boxes can be checked and peace of mind achieved;

— if a major standard recommends against specific versions or setup, we will comply with it so boxes can be checked and peace of mind achieved; Adoption — it would be great to recommend TLS 1.3 only, but we would be severely limiting the number of people who can talk with us. So a reasonable balance must be reached between security and adoption.

Security

Implementation issues aside, the SSL and TLS protocols have had a rough history. This is not the fault of the protocol creators though. Several early design decisions were made when researchers had not yet figured out key aspects of secure protocol construction. One such example is the, at the time thought to be safe, MAC-then-Encrypt cryptographic composition. This design decision brought immense pain over the years in the form of padding-oracle attacks, and many creative TLS vulnerability names. Other examples exist, such as the need to accommodate export ciphers: there was a time where encryption was classified as a munition, and thus export restrictions applied. This requirement eventually led to vulnerabilities such as Logjam and FREAK. TLS history is very rich, and quite a few more examples exist.

The recommendations should take into account known attacks and, if possible, mitigate potential future attacks. Please note that the following list is not complete.

Renegotiation attacks — CVE-2009–3555 and CVE-2011–1473

These vulnerabilities are fixed in every non-ancient TLS library and server application. To our surprise, Probely found new instances of CVE-2011–1473 affecting nginx and OpenSSL in the wild. After some investigation, we discovered that it was caused by a change in the OpenSSL 1.1 API. The issue was fixed in OpenSSL and nginx a few months ago. Be aware that, if you are using OpenSSL ≥ 1.1 with nginx stable (1.14 at this time), you are still vulnerable. So, considering the above, our recommendations are:

Ensure that your TLS libraries and servers are up-to-date;

Renegotiation is typically used for rekeying and requesting client certificates. Many major websites disable renegotiation altogether and, unless you have a specific need for it, we recommend you do too;

Regularly test your deployments to make sure that a regression is not introduced.

Padding-oracle attacks — POODLE, LUCKY13, ROBOT, and others

Ensure that your TLS libraries and applications are up-to-date;

Hardcore option: disable CBC ciphers completely. This requires TLS 1.2 with AEAD ciphers, or TLS 1.3. We understand that this may be a controversial recommendation because, even if we use TLS 1.2, enabling AEAD ciphers only may turn into a compatibility minefield. The motivation is that, over the years, many attacks have exploited CBC padding-oracles due to the problematic MAC-then-Encrypt composition. It has been a game of cat and mouse between security engineers and security researchers: researchers find new padding-oracles; engineers fix them, hoping that it’s the last time; repeat;

Use TLS 1.3. A source of padding-oracles has been the PKCS#1 v1.5 padding scheme used with RSA. TLS 1.3 uses the improved RSASSA-PSS scheme, which is much more robust.

Downgrade attacks — FREAK, Logjam, POODLE

Ensure that your TLS libraries and applications are up-to-date;

Ensure that applications enable TLS_FALLBACK_SCSV;

TLS 1.3 has the most reliable protection mechanism against these types of attacks, using, among other things, the ServerRandom value in a clever way.

Compression attacks — CRIME and BREACH

CRIME and BREACH are chosen-plaintext attacks, that leverage compression to create side-channels and recover the plaintext. Both attacks rely on code running on the victim’s computer to work, e.g. malicious JavaScript, and an eavesdropper that can observe encrypted traffic.

Ensure that your TLS libraries and applications are up-to-date;

For CRIME, disable TLS compression;

BREACH works at the application level and requires that secret data is echoed back in the page body, like CSRF tokens. The tradeoff between better performance provided by compression, and potential exposure to this attack should be weighted.

Insecure cipher attacks — 64-bit ciphers (Sweet32) and RC4

Disable all 64-bit block ciphers (DES, 3DES, others);

Disable RC4.

DROWN

Ensure that all your TLS libraries and servers are up-to-date. In some scenarios, DROWN relies on attacking old and unmaintained SSL 2.0 servers to compromise keys shared between both old and new TLS servers.

BEAST

Ensure that your clients (browsers) are updated. BEAST is a client-side attack;

Protocol-level solution: enable TLS ≥ 1.1 only.

Insecure protocol versions

All SSL versions have known vulnerabilities and should be disabled;

TLS 1.0 is vulnerable to BEAST, a client-side vulnerability and clients should be updated accordingly. However, there are no guarantees that all TLS 1.0 clients are patched. The preferable solution is to disable TLS 1.0;

If you can, we strongly recommend using AEAD ciphers only. This implies using TLS 1.2 and above.

Adequate key sizes

X.509 certificates: use RSA with at least 2048-bit keys; ECDSA with at least 256-bit keys; use a strong hash function for the signature algorithm, e.g. SHA256.

Key exchange: use ECDHE with least 256-bit keys;

Encryption: use AES with least 128-bit keys or ChaCha20, which uses 256-bit keys;

Integrity: Use HMAC with at least 256-bit keys, e.g. HMAC-SHA256 or Poly1305, which uses 256 bit keys.

Implementation errors — goto fail; Heartbleed, and many others

Ensure that your TLS libraries and applications are up-to-date :).

SSLstrip-like attacks

While not an issue with the TLS protocol itself, some attacks attempt to redirect the victim to a version of a website without HTTPS, thus without any security guarantee that TLS provides.

Enable HTTP Strict Transport Security (HSTS). This is an application configuration option, not a TLS setting.

Performance

AEAD ciphers — One great thing about TLS 1.2 is that it supports AEAD ciphers. This means that encryption and authentication are now tied into one cryptographic primitive. The best examples we have right now are AES-GCM, which can go really fast on CPUs supporting AES-NI; and ChaCha20-Poly1350, which is very fast, even in software, and is recommended for mobile devices. So, in addition to being more secure, TLS 1.2 is actually faster than earlier versions.

OCSP Stapling — Enables faster TLS handshakes by appending certificate revocation data during the initial handshake. Stapling allows clients to avoid making additional connections to verify certificate validity. This is not always possible to enable, as servers will require outbound connectivity.

TLS 1.3 1-RTT and 0-RTT handshakes — as discussed earlier, TLS 1.3 has a faster handshake that completes in 1-RTT. Additionally, it has a particular session resumption mode where, under certain conditions, it is possible to send data to the server on the first flight (0-RTT).

Compliance

Starting June 30, 2018, PCI 3.1 forbids all SSL versions, and TLS versions before 1.1:

30 June 2018 is the deadline for disabling SSL/early TLS and implementing a more secure encryption protocol — TLS 1.1 or higher (TLS v1.2 is strongly encouraged) in order to meet the PCI Data Security Standard (PCI DSS) for safeguarding payment data.

NIST requirements are even stricter for government-only applications, requiring TLS 1.2 and above:

Servers that support government-only applications shall be configured to use TLS 1.2, and should be configured to use TLS 1.3. These servers should not be configured to use TLS 1.1, and shall not use TLS 1.0, SSL 3.0, or SSL 2.0.

Adoption

According to recent sources, TLS 1.2 adoption is at around 94%. This gives us some confidence that disabling previous TLS versions is a viable option. In December 2017, Cloudflare reported that TLS 1.1 represented only 0.38% of total connections. The recent PCI Council requirement of having TLS 1.0 disabled to achieve compliance also helped to push the adoption level. Taking all this information into account, it seems reasonable to support only TLS 1.2 and above.

So, what are the recommendations?

We suggest two modern configurations, both supporting TLS 1.2 and above. As discussed earlier, this seems like a reasonable decision in 2019. The first configuration is more lenient and provides better compatibility, while still using modern cryptography. The second configuration is very strict and disables CBC ciphers altogether. Note that the second option should work with modern browsers, but will fail, for example, with Java 7. If you know for sure that your traffic is predominantly coming from modern browsers and are willing to sacrifice the long-tail, or have control over both clients and servers, go a(h)ead.

Common recommendations

Enable TLS 1.2 and TLS 1.3;

Enable HTTP Strict Transport Security (HSTS);

Prefer server cipher order;

Enable OCSP stapling, if possible;

Disable TLS compression;

Disable TLS renegotiation;

As we found out with CVE-2011–1473, regularly test your deployments to make sure that a regression is not introduced.

In addition to the cipher suite names as defined by OpenSSL, we provide the standard IANA cipher suite names. This should make it easier to enable the configurations on other TLS libraries, such as NSS, GnuTLS, SChannel, and others.

Option A— Modern compatible TLS cipher suites

OpenSSL

TLS13-AES-256-GCM-SHA384: TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

IANA

TLS_AES_256_GCM_SHA384

TLS_CHACHA20_POLY1305_SHA256

TLS_AES_128_GCM_SHA256

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384

TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256

Option B — Modern strict TLS cipher suites

OpenSSL

TLS13-AES-256-GCM-SHA384: TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256

IANA

TLS_AES_256_GCM_SHA384

TLS_CHACHA20_POLY1305_SHA256

TLS_AES_128_GCM_SHA256

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Examples

We created an Nginx-based TLS reverse proxy container with modern TLS settings and automatic certificate renewals. You can find it here.

It might be one of these 🙄Photo by frank mckenna.

The reverse proxy can be placed in front of an existing HTTP website to enable HTTPS functionality with, hopefully, minimal hassle. You can think of it as a (limited) TLS terminator. You are free to change the configuration to better suit your needs, of course.