TLS Internals
Transport Layer Security is the protocol that protects the overwhelming majority of internet traffic in 2026. It sits between the application and the transport — typically TCP, increasingly QUIC over UDP — and provides three things: confidentiality of the data in transit, integrity of that data against tampering, and authentication of the server (and optionally the client). The protocol is the result of thirty years of incremental design, partial standardization, repeated attacks, and slow but steady improvement. The current version, TLS 1.3, is the cleanest and most defensible of the lot. The previous version, TLS 1.2, remains widely deployed and will continue to be for years.
This page is the deep-dive companion to the Cryptography umbrella overview. The scope here is the protocol itself — how it works, where the surface area lives, and the catalog of attacks that have shaped its current form. Certificate management is covered in the Public Key Infrastructure page; key management more generally has its own page.
Where TLS sits
TLS is an application-layer protocol that provides a secure stream-oriented byte channel to whatever runs on top of it. The OSI position is awkward — TLS does not fit cleanly into a single layer — but in practice it sits between the transport and the application. HTTPS is HTTP over TLS over TCP. The TLS layer does not know what bytes flow through it; the application above does not need to know that TLS is encrypting them. This separation is structurally important and is the reason the same TLS implementation can protect HTTP, SMTP, IMAP, LDAP, MQTT, and every other application protocol with relatively minor adaptation.
The protocol comes in two pieces that are useful to distinguish:
The handshake protocol is the initial exchange in which the client and server authenticate each other, negotiate parameters, and derive shared keys. The handshake runs once per session and is the cryptographically interesting part.
The record protocol is the ongoing layer that takes application data, encrypts it under the keys negotiated in the handshake, and ships it across the underlying transport. The record protocol runs continuously throughout the session, processes the bulk of the traffic, and is where the per-byte performance lives.
Most of the interesting design surface and most of the historical attacks live in the handshake. The record protocol is structurally simpler, and modern versions have converged on AEAD-only constructions that have eliminated most of the recurring attack patterns.
The version history
TLS has a longer history than the name suggests, because the protocol started life as SSL (Secure Sockets Layer) at Netscape in the early 1990s. The naming changed when the IETF took the protocol over for standardization.
- SSL 1.0 (1994) was never released publicly. It had known cryptographic weaknesses that prevented Netscape from shipping it.
- SSL 2.0 (1995) was the first publicly released version. It had a long list of structural defects — no authentication of the handshake, weak MAC integration, vulnerability to truncation attacks — and was effectively broken from launch. It was prohibited by RFC 6176 in 2011 and removed from major libraries by 2015. DROWN (2016) was an attack that exploited servers that still supported SSL 2.0 to break TLS connections that used RSA key exchange under the same key, by using the SSL 2.0 implementation as a decryption oracle. The attack demonstrated that even disabled-by-default-but-still-supported old versions remained dangerous.
- SSL 3.0 (1996) was a complete redesign. It fixed most of SSL 2.0’s structural issues but retained CBC modes with MAC-then-encrypt composition that produced the POODLE attack (2014), exploiting the predictable nature of SSL 3.0’s CBC padding to recover plaintext one byte at a time. POODLE was the trigger for the industry-wide deprecation of SSL 3.0; the protocol is now thoroughly dead.
- TLS 1.0 (1999, RFC 2246) was essentially SSL 3.0 with the protocol number bumped to indicate IETF stewardship and a small set of cryptographic improvements. TLS 1.0 inherited most of SSL 3.0’s record-layer design and most of its weaknesses. Deprecated by major browsers in 2020.
- TLS 1.1 (2006, RFC 4346) added explicit IVs to CBC mode to mitigate predictable-IV attacks (specifically the BEAST family). TLS 1.1 saw limited deployment; most installations skipped it and went directly to 1.2.
- TLS 1.2 (2008, RFC 5246) was the major modernization. Added AEAD cipher suites (AES-GCM, ChaCha20-Poly1305), added negotiable hash functions (allowing SHA-256 and beyond instead of being locked to SHA-1/MD5), added the signature_algorithms extension, and provided enough flexibility that the protocol could be configured securely. TLS 1.2 is still the dominant deployed version in 2026 by traffic volume, though TLS 1.3 is gaining steadily.
- TLS 1.3 (2018, RFC 8446) is the clean-slate redesign. Mandatory forward secrecy, AEAD-only cipher suites, encrypted handshake, simpler key schedule, faster handshake (1-RTT, optionally 0-RTT), removal of compression (which had caused CRIME), removal of renegotiation (which had caused the Triple Handshake attack), removal of static RSA key exchange (which had caused decades of Bleichenbacher attacks). It is the version that takes the lessons of three decades of attacks and bakes them into the protocol design.
The TLS 1.2 handshake
TLS 1.2 remains widely deployed, so its handshake structure is worth understanding even though TLS 1.3 has supplanted it for new deployments.
A typical TLS 1.2 handshake with ECDHE key exchange:
- ClientHello (client → server). The client sends its supported TLS versions, supported cipher suites, supported elliptic curves, supported signature algorithms, supported extensions (including SNI for routing), and a random value.
- ServerHello (server → client). The server picks a cipher suite from the client’s list, sends its random value, and selects extensions.
- Certificate (server → client). The server sends its certificate chain.
- ServerKeyExchange (server → client). For ECDHE suites, the server sends its ephemeral elliptic curve public key, signed with its certificate’s private key.
- ServerHelloDone (server → client). Signals end of server messages.
- ClientKeyExchange (client → server). The client sends its ephemeral elliptic curve public key.
- ChangeCipherSpec (client → server). Signals that subsequent records will be encrypted.
- Finished (client → server). A hash of the entire handshake so far, encrypted with the new keys. Provides integrity over the negotiation.
- ChangeCipherSpec (server → client). Same signal from the server side.
- Finished (server → client). Server’s handshake hash.
Two full round-trips before any application data can be sent. The handshake takes meaningful time on high-latency links, and the certificate and key exchange messages have non-trivial sizes — for some connections, the handshake bytes dominate the first few KB of traffic.
The performance cost of the handshake is one of the structural concerns TLS 1.3 set out to address.
TLS 1.3 — what actually changed
TLS 1.3 keeps the same protocol position and the same high-level abstraction (encrypted stream over a transport) but redesigns the handshake substantially. Six changes are worth understanding individually.
One-RTT handshake. The client speculatively sends its key share in the ClientHello, the server responds with its key share in the ServerHello, both parties derive the session keys, and the server can send application data in its very next message. The handshake completes in a single round-trip in the common case, with the client able to send application data in its next message after receiving the server’s response. The reduction from 2-RTT to 1-RTT is structurally important for connection latency, especially on mobile networks.
Mandatory forward secrecy. TLS 1.3 supports only ephemeral Diffie-Hellman (DHE) and ephemeral elliptic curve Diffie-Hellman (ECDHE) key exchange. Static RSA key exchange, which had been the dominant mechanism in TLS 1.0/1.1/1.2 deployments, is removed. Every TLS 1.3 session is forward-secret by construction — a compromise of the server’s long-term private key does not retroactively decrypt past sessions. This single change eliminates an enormous class of historical concerns.
AEAD-only. TLS 1.3 supports only AEAD cipher suites: AES-GCM (128-bit and 256-bit variants), ChaCha20-Poly1305, and AES-CCM. CBC modes with separate MACs, RC4 stream ciphers, NULL ciphers, and export-grade ciphers are all removed. This eliminates the entire Lucky 13 / POODLE / BEAST attack family that exploited CBC mode failures.
Encrypted handshake. From the ServerHello onward, the handshake is encrypted using keys derived from the initial key exchange. The certificate, the certificate verification, and the handshake hash are all protected from passive eavesdroppers. The only handshake messages an eavesdropper can see in cleartext are the ClientHello and ServerHello — and even those are progressively being encrypted through Encrypted Client Hello (ECH), which is rolling out in 2024-2026.
Simplified cipher suite negotiation. TLS 1.2 cipher suites bundled the key exchange, authentication, bulk cipher, and MAC into a single name (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256). TLS 1.3 cipher suites name only the bulk cipher and the HKDF hash (TLS_AES_128_GCM_SHA256), with key exchange and authentication negotiated separately. The change dramatically reduces the combinatorial explosion of supported suites — TLS 1.3 has five standard cipher suites, against the hundreds in TLS 1.2.
Renegotiation removed. TLS 1.2 supported renegotiation (mid-session re-handshake), which produced the Triple Handshake (2014) and several other attacks. TLS 1.3 removes renegotiation entirely, replacing it with explicit post-handshake authentication and key update mechanisms that do not have the same attack surface.
The net effect: TLS 1.3 is faster, has a smaller attack surface, and is structurally harder to misconfigure than TLS 1.2. The deployment lag is real (TLS 1.3 adoption is still climbing through the mid-2020s), but the direction of travel is clear.
The key schedule
TLS 1.3’s key schedule deserves its own treatment because it is one of the cleaner uses of HKDF in any deployed protocol.
The schedule starts from three possible inputs: an early secret (used for 0-RTT and PSK resumption), a handshake secret (derived from the ECDHE exchange), and a master secret (derived from the handshake). Each of these is processed through HKDF-Extract to produce a uniformly-random secret, then HKDF-Expand-Label is used to derive specific keys for specific purposes — client handshake traffic key, server handshake traffic key, client application traffic key, server application traffic key, exporter master secret, resumption master secret.
The structure has three properties that matter for security analysis:
- Domain separation. Every derived key includes a context string (
"c hs traffic","s ap traffic", etc.) in the Expand-Label call. This makes it cryptographically infeasible for a key derived for one purpose to be misused as a key for another purpose, even if the inputs are similar. - Composability. The schedule cleanly chains multiple secrets (early → handshake → master), with each level fed into the next via Extract. This lets PSK resumption fit naturally into the same schedule as a full handshake.
- Key update support. New traffic keys can be derived from existing application traffic keys without re-running the handshake, supporting long-lived connections that periodically rotate their record-layer keys.
The TLS 1.2 key derivation, by comparison, used a custom PRF construction that has been shown to be analytically awkward — not broken, but not as cleanly defensible as HKDF. TLS 1.3’s switch to HKDF was a deliberate choice to use a primitive with strong analytic foundations.
Session resumption
A full TLS handshake is expensive — multiple round-trips, public-key operations, certificate parsing. For repeat connections to the same server, the protocol supports session resumption that skips most of the handshake by reusing material from a prior session.
Session IDs (TLS 1.0 through 1.2) had the server cache the session state and return a small identifier the client could present on a future connection. The mechanism worked but required server-side state and was awkward in load-balanced environments.
Session tickets (RFC 5077, supported in TLS 1.0 through 1.2) had the server send an encrypted blob of session state back to the client, which the client presented on a future connection. The server decrypts the ticket and recovers the session state without needing to maintain a cache. Stateless on the server side, which fit modern deployment patterns better. The mechanism has its own concerns — ticket key rotation is operationally important, and the same ticket key across a fleet of servers becomes a long-term sensitive secret.
TLS 1.3 PSK resumption unifies these mechanisms under a single pre-shared-key (PSK) abstraction. A successful TLS 1.3 handshake produces a resumption master secret, which can be used to derive PSKs for future connections. The same machinery supports both stateful session caches and stateless session tickets.
0-RTT data, introduced in TLS 1.3, lets the client send application data alongside the very first ClientHello on a resumed connection, encrypted under a PSK-derived key. The latency benefit is significant — 0 round-trips before useful data flows — but the security tradeoff is real. 0-RTT data does not have forward secrecy (the PSK is reused across sessions), and it is replayable: an attacker who captures the 0-RTT data and replays it later will produce the same effect on the server. The TLS 1.3 specification explicitly limits 0-RTT to idempotent operations, but enforcing that at the application layer is the application’s responsibility. The Cloudflare and Google deployments of 0-RTT include extensive application-side replay-detection machinery to make it safe in practice.
The extension ecosystem
TLS extensions, introduced in TLS 1.2 and refined in 1.3, are how the protocol gets new capabilities without breaking compatibility. A few extensions matter enough to know individually.
Server Name Indication (SNI), specified in RFC 6066, lets the client tell the server which hostname it intends to connect to in the unencrypted ClientHello. SNI is what makes name-based virtual hosting work on HTTPS — a single IP address can serve TLS for many domains because the server picks the right certificate based on the SNI. SNI is now effectively universal. Its downside is that it is in cleartext, which means a network observer can see which hostname a client is connecting to, even though the application data is encrypted.
Encrypted Client Hello (ECH), currently in draft and being rolled out incrementally by Cloudflare, Mozilla, and Google through 2024-2026, encrypts the entire ClientHello including the SNI. The mechanism uses a public key advertised in DNS to encrypt the inner ClientHello to a key the client-fronting server can decrypt. ECH closes the SNI-visibility privacy gap that has persisted since SNI was introduced. Deployment depends on coordination across DNS, certificate management, and client implementations, so the rollout has been gradual.
Application-Layer Protocol Negotiation (ALPN), specified in RFC 7301, lets the client and server agree on which higher-layer protocol they’ll use after the handshake. This is how a single TLS port can serve HTTP/1.1, HTTP/2, and HTTP/3 (over QUIC) without ambiguity, and how the client picks which one to use.
Key shares (TLS 1.3) are the extension that carries the ECDHE public values for the speculative key exchange in the ClientHello. The client offers public values for several key exchange algorithms it supports, and the server picks one.
Signed Certificate Timestamps (SCTs), used for Certificate Transparency, are embedded in the certificate but can also be delivered as a TLS extension during the handshake for certificates that don’t embed them.
Supported groups and signature algorithms extensions let the client advertise which elliptic curves and which signature schemes it supports, so the server can pick parameters the client can actually verify.
The attack catalog
TLS has accumulated a long list of named attacks, mostly against TLS 1.0/1.1/1.2. The catalog is worth knowing because each attack name is a piece of historical context that explains why a particular feature was added, deprecated, or restructured in TLS 1.3.
BEAST (2011) exploited predictable initialization vectors in TLS 1.0’s CBC mode to recover small amounts of plaintext by injecting chosen-plaintext data into a session. Mitigated by 1/n-1 record splitting in clients and ultimately by TLS 1.1’s explicit IVs. Triggered the migration away from TLS 1.0.
CRIME (2012) exploited TLS-level compression to leak plaintext bytes by observing compressed ciphertext sizes when known-plaintext was injected. Compression was disabled in TLS for cleartext-injectable contexts; TLS 1.3 removed compression entirely.
BREACH (2013) is essentially CRIME applied to HTTP-level compression. The TLS protocol cannot mitigate it because the compression happens above TLS. Mitigation is application-level: don’t reflect secrets and attacker-controlled data into the same compressed response.
Lucky 13 (2013) exploited timing differences in CBC-mode record processing to recover plaintext through padding oracle attacks. The mitigation in TLS 1.2 was constant-time padding verification; TLS 1.3 eliminated CBC modes entirely.
POODLE (2014) exploited SSL 3.0’s predictable CBC padding to recover plaintext. Triggered the industry-wide kill of SSL 3.0.
Heartbleed (2014) was an OpenSSL implementation bug, not a TLS protocol flaw. The Heartbeat extension implementation read beyond a buffer, leaking up to 64 KB of process memory per request. The protocol was fine; the implementation was wrong. The incident triggered the formation of the Core Infrastructure Initiative to fund open-source security work, the rewrite of large portions of OpenSSL, and the rise of alternatives like BoringSSL and LibreSSL.
Triple Handshake (2014) exploited TLS 1.2 renegotiation to bind one session’s authentication context to another session’s keys, breaking client authentication assumptions. Mitigated by the extended master secret extension (RFC 7627); TLS 1.3 removed renegotiation.
FREAK (2015) exploited TLS servers that still supported export-grade RSA cipher suites (mandated by US export restrictions in the 1990s and never fully removed from many servers). An attacker could downgrade the connection to 512-bit RSA, which could be broken in hours on modern hardware. Triggered the removal of export ciphers from major TLS libraries.
Logjam (2015) exploited weak Diffie-Hellman parameters in finite-field DH cipher suites, with similar export-grade ancestry to FREAK. Many servers shared the same DH parameters, making precomputation attacks economical. Triggered the migration to elliptic curve key exchange.
DROWN (2016) exploited servers that still supported SSL 2.0 (and shared an RSA key with their TLS service) to use the SSL 2.0 implementation as a decryption oracle. Demonstrated that disabled-but-still-running old versions remained dangerous.
Sweet32 (2016) exploited the small (64-bit) block size of 3DES and other legacy block ciphers to find collisions in long-lived connections, recovering plaintext. Triggered the removal of 3DES from TLS cipher suite lists.
ROBOT (2017) was Bleichenbacher’s RSA PKCS#1 v1.5 padding oracle attack from 1998, rediscovered in modern TLS implementations. Many supposedly-mitigated implementations were still vulnerable through subtle timing or behavioral differences. Triggered another round of mitigations across major TLS libraries.
Raccoon (2020) exploited timing differences in DH-RSA cipher suites’ key derivation. Narrow attack with low practical impact, but another example of how even well-studied protocols can leak through unexpected side channels.
Marvin (2023) generalized previous Bleichenbacher attacks and demonstrated that many implementations were still vulnerable through timing differences in their error handling. The attack again highlighted that the PKCS#1 v1.5 padding format remains a structural liability and that complete mitigation through implementation work has been elusive.
The pattern across the catalog: most TLS attacks have been against the older versions and against features (compression, renegotiation, CBC modes, static RSA, weak parameters) that TLS 1.3 has removed. TLS 1.3 itself has held up well — no significant attack against the core protocol has materialized in the seven years since its publication.
Configuration in practice
Mozilla maintains the canonical reference for TLS configuration profiles, updated periodically with the current state of the art. The three tiers are:
- Modern. TLS 1.3 only, AEAD only, ECDHE only, ECC certificates. Suitable for services where every client can be expected to be modern. Smallest configuration, smallest attack surface.
- Intermediate. TLS 1.2 and 1.3, AEAD ciphers preferred, ECDHE preferred. Suitable for services that need to support a mix of clients. The pragmatic default for most public-facing services in 2026.
- Old. TLS 1.0 through 1.3, broader cipher suite list. For services that must support legacy clients (old embedded devices, some payment terminals, certain IoT fleets). Should be a deliberate choice, not a default.
The Mozilla generator at ssl-config.mozilla.org produces ready-to-deploy configurations for nginx, Apache, HAProxy, and most major TLS-terminating servers based on the chosen tier and the server version. Using it is the right starting point for any new TLS deployment.
Beyond the cipher suite list, several configuration knobs matter:
HSTS (HTTP Strict Transport Security), specified in RFC 6797, is an HTTP response header that tells browsers to refuse HTTP connections to the named host for a specified duration. HSTS turns a one-time HTTPS interaction into a persistent commitment, which prevents downgrade attacks. HSTS preload is the further step of submitting the domain to a browser-maintained list so that even the first connection is HTTPS-only. Both should be enabled for any production HTTPS service.
Certificate pinning through the HTTP Public Key Pinning (HPKP) header was an attempt to let sites pin specific certificate keys at the browser level. It was so error-prone in production that browsers removed support in 2018. The replacement is Expect-CT, which is being supplanted by built-in CT enforcement in modern browsers. For mobile applications, native certificate pinning at the application layer remains a reasonable defense; for web applications, it generally is not.
OCSP stapling should be enabled wherever the TLS-terminating server supports it. The reduction in connection latency and the privacy benefit (the client does not have to query the CA’s OCSP responder) make stapling worth the configuration cost.
Performance
The handshake cost dominates TLS performance for short connections. For HTTPS APIs that handle one request per connection, a TLS handshake adds typically 50-300 milliseconds of latency depending on RTT and the parties’ public-key performance. Session resumption (PSK in 1.3, tickets in 1.2) eliminates most of this cost on repeat connections to the same server, reducing the handshake to a single round-trip with no public-key operations.
0-RTT in TLS 1.3 further reduces handshake latency to zero round-trips for resumed connections, at the cost of replay vulnerability for the 0-RTT data. The tradeoff is appropriate for some workloads (cached static content, idempotent GETs) and inappropriate for others (state-modifying requests, anything involving payment).
TLS False Start is a TLS 1.2 optimization that lets the client send application data immediately after sending its Finished message, without waiting for the server’s Finished. Saves one round-trip on the initial handshake. Has compatibility issues with some servers and is being supplanted by TLS 1.3’s native 1-RTT handshake.
QUIC and HTTP/3 embed TLS 1.3 directly into the QUIC transport, with the TLS handshake interleaved with the QUIC connection setup. The result is even lower handshake latency than TLS 1.3 over TCP, plus QUIC’s other benefits (head-of-line blocking resistance, connection migration). HTTP/3 is the deployed shape of this combination and now handles a substantial fraction of large-vendor traffic.
For bulk-data throughput, modern TLS with AES-NI hardware acceleration is bounded by memory bandwidth, not by the cipher cost. The handshake is the bottleneck; the steady-state throughput rarely is.
Mutual TLS
Mutual TLS (mTLS) is the configuration in which the client also presents a certificate during the handshake and the server verifies it. The mechanism turns TLS into a mutual authentication protocol rather than a server-authentication-only one.
In TLS 1.2 and earlier, mTLS happens through an extra round of handshake messages: the server sends a CertificateRequest, the client responds with its Certificate and CertificateVerify messages. In TLS 1.3, the same exchange is integrated cleanly into the 1-RTT handshake.
mTLS is the dominant authentication mechanism for service-to-service communication in modern microservice and zero-trust architectures. Service meshes (Istio, Linkerd, Consul Connect) automate the certificate distribution and rotation that makes mTLS operationally tractable. The cost — every service needs a certificate, certificates have to rotate, the PKI has to be maintained — is real but bearable when automated.
For end-user authentication on the web, mTLS has historically been rare due to certificate management UX issues. It remains the standard for high-security applications (government access systems, smart card login, some VPN authentication).
Post-quantum TLS
The deployed direction for post-quantum TLS in 2026 is hybrid key exchange: the ClientHello carries both a classical key share (X25519) and a post-quantum key share (ML-KEM-768), the server responds with both, and the session key is derived by combining both outputs through HKDF. The handshake protects against both classical adversaries (in case ML-KEM turns out to have an unexpected classical weakness) and quantum adversaries (the classical X25519 portion provides no protection against quantum).
Cloudflare, Google, and Apple have rolled out hybrid post-quantum key exchange in their respective products through 2023-2025. The handshake size increases meaningfully — ML-KEM-768 adds roughly 2 KB to the ClientHello and similarly to the ServerHello — which has implications for the initial round-trip on slow links and for the QUIC initial packet size. The deployment experience so far has been positive; the size increase is bearable and the handshake performance impact is small.
Post-quantum authentication (replacing ECDSA and RSA signatures in certificates with ML-DSA or SLH-DSA) is further out, primarily because the post-quantum signature sizes are much larger and the certificate chain size impact is substantial. The transition will happen but is not yet deployed at scale.
Standards and references
- RFC 8446 — TLS 1.3.
- RFC 5246 — TLS 1.2 (historical, still operational).
- RFC 8447 — IANA registry assignments and procedures for TLS parameters.
- RFC 6066 — TLS extension definitions (SNI, status_request, max_fragment_length, etc.).
- RFC 7301 — ALPN.
- RFC 7627 — TLS Session Hash and Extended Master Secret extension.
- RFC 9001 — Using TLS to Secure QUIC.
- Mozilla SSL Configuration Generator —
ssl-config.mozilla.org. - SSL Labs test suite —
ssllabs.com/ssltest— comprehensive testing for any public TLS endpoint.
What to actually use in 2026
For new TLS deployments, the practical configuration is:
- TLS 1.3 as the primary version, TLS 1.2 supported only when legacy clients require it. Disable 1.0 and 1.1 entirely; they are not just discouraged, they are dangerous.
- Cipher suites: TLS 1.3 standard cipher suites (TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256). For TLS 1.2 fallback, ECDHE-ECDSA-AES128-GCM-SHA256 and ECDHE-RSA-AES128-GCM-SHA256 cover most clients.
- Key exchange: X25519 first, P-256 as a fallback. For post-quantum readiness, enable hybrid X25519+ML-KEM-768 if the library supports it (BoringSSL, OpenSSL 3.5+, Go 1.24+ all do).
- Certificate keys: ECDSA P-256 or Ed25519 for new certificates. RSA-2048 only for compatibility with older clients that cannot verify ECC certificates.
- HSTS enabled with a long max-age (one year is the typical choice),
includeSubDomainsif all subdomains are HTTPS, and HSTS preload submission for the apex domain. - OCSP stapling enabled.
- Session resumption enabled, with regular rotation of ticket keys (daily or more frequent for high-security services).
- 0-RTT only enabled for endpoints that handle exclusively idempotent operations, and only with application-layer replay protection where the application’s threat model requires it.
Avoid: TLS 1.0, TLS 1.1, SSL 3.0 in any form, RC4 cipher suites, 3DES cipher suites, NULL ciphers, export ciphers, static RSA key exchange (RSA in the cipher suite name without DHE/ECDHE), CBC mode cipher suites in TLS 1.2 (use the GCM equivalents), and any certificate with an RSA key smaller than 2048 bits or with SHA-1 anywhere in the signature chain.
TLS 1.3 has gotten this corner of cryptography in much better shape than it was a decade ago. The structural decisions — mandatory forward secrecy, AEAD-only, encrypted handshake, simpler cipher suite list — collectively eliminate most of the historical attack surface. The work that remains is in the configuration, the certificate management, and the migration of legacy clients onto modern code paths. Most of the protocol-level work is done.