Configuration
When it comes to protocol configuration, your choices are likely to be influenced by a combination of security, interoperability, and regulatory requirements. In the ideal world, focusing on security alone, you would allow only TLS 1.3 and disable all other protocol versions. But that works only in well-understood environments; although modern browsers support TLS 1.3, many other products and tools still don’t.
Use secure protocols
A website intended for public use needs to support TLS 1.3 and TLS 1.2 at minimum. It’s very likely that you don’t need TLS 1.1 and TLS 1.0; modern browsers no longer support them. The remaining protocols, SSL 3 and SSL 2, are both obsolete and insecure.
- SSL 2 is completely broken and must not be used. This is the first–ever protocol version and is so bad that it can be used to attack even well-configured servers that use overlapping certificates or private keys (the so-called DROWN attack).
- SSL 3 is better, but still insecure when used with HTTP because of the POODLE attack. It’s also very weak when used with other protocols. It’s obsolete and lacks essential security capabilities. Don’t use.
- TLS 1.0 is a legacy protocol that lacks essential security capabilities. Modern clients no longer support this protocol version, but there are still old clients out there that need it. TLS 1.0 is vulnerable to the BEAST attack, although most browsers have deployed mitigations as a workaround.
- TLS 1.1 is also a legacy protocol that lacks modern capabilities. There are hardly any clients that support this version but don’t support TLS 1.2.
- TLS 1.2 is a relatively modern protocol that can provide good security, but it supports both bad and good cryptographic primitives. It can be used securely with some effort. This protocol version is necessary in order to support a wide range of customers.
- TLS 1.3 is a completely reworked revision of TLS that supports only secure primitives. This protocol version, which modern browsers support, should be what protects most of your network communication.
If you need to support very old clients and wish to continue to use TLS 1.0, base your decisions on evidence, not fear. This protocol version is no longer considered secure, so tread carefully.
Use forward secrecy
Forward secrecy (also known as perfect forward secrecy) is a feature of cryptographic protocols that ensures that every communication (e.g., a connection) uses a different set of encryption keys. Such keys are called ephemeral because they are discarded after they are no longer needed. Ephemeral connection keys do not depend on any long-term keys—for example, the server key. When there is no forward secrecy, an adversary who can record your network traffic and later obtain the server key can also decrypt all past communications.
SSL and TLS initially used only the RSA key exchange that doesn’t support forward secrecy. To fix that, the ephemeral Diffie-Hellman (DHE) and Elliptic Curve Diffie-Hellman (ECDHE) key exchanges were added over time, along with some protocol improvements in TLS 1.3. Don’t be confused by the fact that RSA can be used for key exchange and authentication; the former is bad, but the latter is fine.
In TLS 1.2 and earlier protocol versions, the key exchange (and thus forward secrecy) is controlled via cipher suite configuration. Therefore, you want to ensure that all enabled suites embed the keywords DHE and ECDHE. In TLS 1.3, all suites support forward secrecy; the RSA key exchange is no longer supported.
Use a strong key exchange
In recent years, the DHE key exchange fell out of fashion, so much so that modern clients no longer support it. As a result, there is only one widely supported secure option for the key exchange, and that’s ECDHE. Although DHE suites do have some issues, they are not likely to be a problem in practice if used only as fallback. You shouldn’t use the RSA key exchange (not to be confused with RSA authentication) because in that case you lose forward security.
For key exchange to be secure, ECDHE and DHE have to be used with secure parameters. For ECDHE, the parameters are called named curves and only two are practical: X25519 and P-256 (also known as sec256r1). For DHE (if using), ensure the parameters provide 2,048 bits of security. Some server software provides secure DHE parameters out of the box; with others, you’ll have to provide your own.
If long-term security is of concern, follow the efforts to transition to post-quantum cryptography. New, quantum-resistant key exchange standards are in the process of being developed and tested.
Prioritize the best cipher suites
In TLS, servers are in the best position to determine the most secure communication option to use with the connecting clients. That’s because the first step of the TLS handshake involves the client sending a list of supported features. What remains is for the server to choose what feature to proceed with.
Unfortunately, some platforms don’t actively choose the best option, instead resorting to choosing the first one offered by clients. For best results, check what your platform does and enable server preference wherever possible. In general, avoid platforms that don’t support server preference enforcement as it may not be possible to configure them securely in a general case.
Use secure cipher suites
In TLS, cipher suites are the most visible aspect of server configuration. Usually a lot of effort goes into understanding what options are available, secure, and required to achieve secure communication. Determining what cipher suites to use has traditionally been difficult; over time, the TLS protocol accumulated a very large number of suites, most of which are considered insecure or inadequate today.
On the positive side, TLS 1.3, the most recent incarnation of the TLS protocol, supports only a handful of suites, and all of them are secure. If you base your configuration on this protocol version, all connections with clients that also support it will be secure with ease. You should lead with the following three suites (which are usually enabled by default anyway):
TLS_AES_128_GCM_SHA256 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_256_GCM_SHA384
When it comes to TLS 1.2, you should rely on cipher suites that provide strong key exchange, forward secrecy, and AEAD (authenticated encryption with associated data) encryption of 128 bits. Use AES and ChaCha20 encryption algorithms. Your configuration can continue to utilize non-AEAD suites, but only to support very old clients, if that’s necessary. Don’t use anything else unless you’re a cryptographer and know what you’re doing.
The preceding recommendations, translated to specific TLS 1.2 suites, yields the following:
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_256_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
This configuration is designed with both security and performance in mind. It supports both ECDSA and RSA keys, with priority given to the former, which is faster. It also includes more suites than strictly necessary in order to support a wider range of clients. If you’re using OpenSSL, the following configuration is exactly the same but uses the nonstandard suite names that OpenSSL will understand:
ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256
I recommend that you always configure OpenSSL with an explicit list of desired suites, as indicated earlier. This approach is the simplest and provides great visibility into exactly what is enabled. With OpenSSL, it’s also possible to use the legacy, keyword-based configuration approach, but that leads to opaque configurations that are difficult to understand and often end up doing the wrong thing.
Ensure ticket keys are rotated
In TLS, session resumption is implemented using one of two approaches. The original approach was to have the server keep the state in persistent storage. Later, session tickets were added, and they work like HTTP cookies. Session state is packaged into a binary blob, encrypted, and sent back to the client to store and send with all subsequent connections.
When session tickets are used, the security of all connections depends on the main ticket key. This key is used to safely encrypt and decrypt session tickets. The security of the ticket key is an area in which current server software doesn’t provide adequate controls. Most applications that rely on OpenSSL use implicit ticket keys that are created on server startup and stay the same for the duration of the process. If the process stays up for weeks and months, so does the ticket key. Backdooring applications is relatively easy for skilled attackers; you can inject a static, never-changing ticket key to give you the ability to decrypt all communication. The most secure deployments of TLS configure ticket keys explicitly and rotate them on a predetermined schedule— for example, daily.
Session ticket security is very important to get right if you’re deploying TLS 1.2. In this situation, knowing the ticket key is all you need to decrypt past communications. TLS 1.3 brought some much-needed improvement in this area. This updated protocol version uses session tickets for authentication, but has an option (enforced by all modern browsers) to perform an ephemeral DiffieHellman handshake on all resumed connections. The end result is that knowing the ticket key is no longer sufficient for passive decryption, making it a much smaller attack vector.
Mitigate known problems
There was a period of time when it was common to learn about new protocol issues, but that now seems to be behind us. At some point we stopped finding new problems; the ones we know about were largely fixed. Then TLS 1.3 came along, which made things much better still. Critical issues at the protocol level are not so common today, but it’s generally accepted that security always deteriorates over time. For that reason, it’s a good practice to be aware of what’s going on. At this point in time, the most likely problems you will encounter are implementation issues in libraries and server software. Apply patches promptly when they become available.
Supporting legacy platforms
Sometimes you’ll find yourself needing to support legacy clients that don’t have the latest and greatest security features. In this case, you will need to reach out for, and enable, certain components that are not ideal but are still acceptable for use in exceptional situations. It could be that the risk of the exploitation is low or that the service is not that valuable, or perhaps you have mitigation measures in place. If you are in this situation, this section is for you; I will outline here some of those imperfect but palatable legacy features. The good news is that it’s generally possible to deploy strong and weak elements at the same time, relying on the TLS negotiation features and server configuration to ensure that individual connections use the best commonly supported features. This means that those weak elements in your configuration will be used only as a last resort.
If you have to resort to using some of these weak encryption components in production, consider splitting your systems into those that are well-configured and those that are intended to serve your legacy clients. Structuring your deployments like that will help you minimize the risk.
RSA private keys
The ECDSA algorithm is gaining in popularity on account of its speed, but you will often find that it’s not supported by some old clients. In this case, fall back to the RSA algorithm. If you care about performance, deploy with two certificates, using both ECDSA and RSA at the same time.
TLS 1.1, TLS 1.0, SSL 3, and SSL 2
Very old user agents won’t support TLS 1.2, so you may need to enable TLS 1.0 for them. This is not terrible and you may find that my recommended suite configuration works for you. If you’re considering SSL 3, you’re dealing with ancient stuff. Are you sure you want to do that? It’s probably best that you seek professional advice. SSL 2 cannot be used securely—and it’s worse than no encryption because this protocol version can be used to exploit secure servers (via DROWN). Nobody cares about TLS 1.1.
Weak Diffie-Hellman key exchange
There are some old clients (e.g., Java before version 8) that can’t use the DH key exchange at 2,048 bits, which is the recommended strength today. You may consider dropping the strength to 1,024 bits to accommodate these clients. If you do, you should generate a unique set of DH parameters on each server. You must not use any of the predefined well-known groups because they can be exploited via a precomputation attack. Anything below 1,024 bits is very easy to exploit.
You need to be aware that if you reduce the strength of the DH key exchange, it will affect both modern and legacy clients. This is one aspect of TLS configuration that cannot be negotiated on a per connection basis. The best approach is to have separate systems for modern and legacy customers. If you can’t do that, preferring the ECDHE key exchange (as in my recommended configuration) will ensure that modern clients all use ECDHE and never attempt DHE.
Weak cipher suites
Once upon a time, it was necessary to make compromises to support some very old user agents—for example, Windows XP and Android. These are bad at cryptography and don’t support either DHE or ECDHE key exchange, not even AES. To support these platforms you’ll need to support the plain old RSA key exchange that doesn’t provide forward security. For Windows XP, you’ll need to support 3DES as well. You very likely don’t need that, but here are some last-resort suites to place at the end of your prioritized list of suites if there is no other way:
TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA.