Every time you load a website, your browser and the server perform a cryptographic negotiation that takes less than a hundred milliseconds. In that sliver of time, they agree on encryption algorithms, verify identity through a certificate chain, generate shared secret keys, and establish a channel that nobody in between can read. You see a padlock icon. Behind it is a protocol that has been attacked, broken, rebuilt, and hardened over two decades. That protocol is TLS, and it’s the reason the internet isn’t a postcard system.

The TLDR

Transport Layer Security (TLS) encrypts the connection between your browser and a server. The handshake negotiates which encryption algorithms to use, authenticates the server through its certificate, and generates session keys. TLS 1.2 uses a multi-step handshake with negotiable cipher suites. TLS 1.3 stripped it down — fewer round trips, no weak ciphers, mandatory forward secrecy. The history of TLS is a graveyard of broken protocols and attacks with dramatic names: BEAST, POODLE, Heartbleed, DROWN. Each one taught the industry something. The current state: TLS 1.3 is solid, but only if you actually disable the older versions that aren’t.

The Reality

SSL 2.0 shipped in 1995. It was broken almost immediately. SSL 3.0 followed, then TLS 1.0, 1.1, 1.2, and finally 1.3 in 2018. Each version patched the flaws of the last, but backward compatibility kept the broken versions alive for years. As of 2025, the internet has largely moved to TLS 1.2 and 1.3, but legacy servers running TLS 1.0 and 1.1 still exist — and every one of them is a target.

The fundamental tension in TLS has always been between security and compatibility. Cipher suites that were considered secure in 2010 are broken in 2025. Protocols that were “good enough” for a decade became liabilities. NIST SP 800-52 Rev. 2 provides the current authoritative guidance: TLS 1.2 minimum, TLS 1.3 preferred, and a specific list of acceptable cipher suites.

How It Works

The TLS 1.2 Handshake

The TLS 1.2 handshake is a four-step dance between client and server. Here’s what happens:

Client                                Server
  |                                      |
  |--- ClientHello ---------------------->|  (supported versions, cipher suites, random)
  |                                      |
  |<--- ServerHello ---------------------|  (chosen version, cipher suite, random)
  |<--- Certificate ---------------------|  (server's X.509 certificate chain)
  |<--- ServerKeyExchange ---------------|  (DH/ECDHE parameters, if applicable)
  |<--- ServerHelloDone -----------------|
  |                                      |
  |--- ClientKeyExchange --------------->|  (pre-master secret or DH public value)
  |--- ChangeCipherSpec ---------------->|  (switching to encrypted mode)
  |--- Finished ------------------------>|  (encrypted verification)
  |                                      |
  |<--- ChangeCipherSpec ----------------|
  |<--- Finished ------------------------|
  |                                      |
  |====== Encrypted Application Data ====|

ClientHello: Your browser sends its supported TLS versions, a list of cipher suites it can use (in preference order), a random value, and optional extensions like Server Name Indication (SNI) — which tells the server which hostname you’re trying to reach, important for servers hosting multiple sites.

ServerHello: The server picks the highest mutually supported TLS version and the strongest mutually supported cipher suite from the client’s list. It sends back its own random value.

Certificate: The server sends its X.509 certificate chain — leaf certificate, intermediate CA(s), and enough information for the client to validate the chain back to a trusted root CA. Your browser walks this chain, checks expiration dates, checks revocation status, and verifies the certificate covers the domain you’re visiting.

Key Exchange: This is where session keys are born. With ECDHE (Elliptic Curve Diffie-Hellman Ephemeral), the server sends its ephemeral public key, the client sends its ephemeral public key, and both sides independently compute the same shared secret without ever transmitting it. That shared secret becomes the basis for the symmetric encryption keys used for the rest of the session.

ChangeCipherSpec and Finished: Both sides switch to encrypted mode and send a verification message (a hash of the entire handshake transcript, encrypted with the new keys). If either side’s Finished message doesn’t validate, the connection is torn down.

Total round trips: 2 RTT before application data can flow. On a high-latency connection, that’s noticeable.

The TLS 1.3 Handshake

TLS 1.3 (RFC 8446) is a fundamental redesign. It cuts the handshake to 1 RTT and removes every weak option:

Client                                Server
  |                                      |
  |--- ClientHello ---------------------->|  (key shares, supported groups, cipher suites)
  |                                      |
  |<--- ServerHello ---------------------|  (key share, cipher suite)
  |<--- EncryptedExtensions -------------|  (encrypted from here on)
  |<--- Certificate ---------------------|
  |<--- CertificateVerify ---------------|
  |<--- Finished ------------------------|
  |                                      |
  |--- Finished ------------------------>|
  |                                      |
  |====== Encrypted Application Data ====|

The key improvement: the client sends key shares in the ClientHello, guessing which key exchange the server will pick. If it guesses right, the handshake completes in one round trip. The server’s response is encrypted from the EncryptedExtensions message onward — even the certificate is hidden from passive observers.

What TLS 1.3 removed: RSA key exchange (no forward secrecy), CBC mode ciphers (vulnerable to padding oracle attacks), RC4, DES, 3DES, static Diffie-Hellman, compression (used by CRIME attack), and renegotiation. If a cipher suite survived the cut, it’s because it earned its place.

0-RTT Resumption: TLS 1.3 supports zero round-trip resumption for repeat connections — the client sends encrypted application data in the very first message. Faster, but with a tradeoff: 0-RTT data is replayable. An attacker who captures a 0-RTT request can replay it. Servers must handle 0-RTT data idempotently or disable it for sensitive operations.

Decoding a Cipher Suite

A TLS cipher suite looks like line noise. Let’s decode one:

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (TLS 1.2 format)

TLS 1.3 simplified the naming. TLS_AES_256_GCM_SHA384 — key exchange is always ECDHE or DHE (forward secrecy is mandatory), so it’s not listed. Authentication is always certificate-based. Only the AEAD cipher and hash are specified.

Forward Secrecy

Forward secrecy (also called perfect forward secrecy) means that compromising the server’s long-term private key doesn’t compromise past session keys. Each session generates ephemeral keys that are discarded after use. Even if an adversary records all encrypted traffic today and steals the server’s private key tomorrow, they can’t decrypt the recorded sessions.

Without forward secrecy (static RSA key exchange), the server’s private key decrypts every past and future session. That’s why TLS 1.3 mandates ephemeral key exchange — the harvest-now-decrypt-later threat makes forward secrecy non-optional.

HSTS — Forcing HTTPS

HTTP Strict Transport Security tells browsers to always use HTTPS for a domain, even if someone types http://. The server sends a header:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

This prevents SSL stripping attacks — where an attacker intercepts the initial HTTP request and downgrades the connection to unencrypted. With HSTS, the browser refuses to connect over HTTP at all. The HSTS preload list goes further: domains are hardcoded into the browser itself, so even the first visit is protected.

How It Gets Exploited

BEAST (2011)

Browser Exploit Against SSL/TLS attacked CBC mode in TLS 1.0 by predicting initialization vectors. The fix: TLS 1.1+ uses random IVs. The real fix: stop using TLS 1.0.

POODLE (2014)

Padding Oracle On Downgraded Legacy Encryption attacked SSL 3.0’s CBC padding. An attacker could force a protocol downgrade from TLS to SSL 3.0, then exploit the padding to decrypt traffic byte by byte. The fix: disable SSL 3.0 entirely. TLS_FALLBACK_SCSV was introduced to prevent forced downgrades.

Heartbleed (2014)

CVE-2014-0160 — a buffer over-read in OpenSSL’s heartbeat extension. An attacker could request more data than was in the heartbeat payload, leaking up to 64KB of server memory per request — including private keys, session tokens, and passwords. Not a TLS protocol flaw — an implementation bug. It affected an estimated 17% of all TLS servers on the internet.

Downgrade Attacks

An active attacker intercepts the handshake and modifies the ClientHello or ServerHello to force weaker cipher suites or older protocol versions. TLS 1.3 mitigates this with a downgrade sentinel — the server embeds a specific value in its random field if it’s been forced to use an older version, and the client detects it.

SSL Stripping

An attacker intercepts the initial HTTP request (before the redirect to HTTPS) and acts as a proxy — maintaining an encrypted connection to the server while serving the victim an unencrypted connection. The victim sees http:// instead of https:// but may not notice. HSTS and HSTS preloading are the defenses. MITRE ATT&CK T1557 documents adversary-in-the-middle techniques that include SSL stripping.

What You Can Do

Disable TLS 1.0 and 1.1 on everything you control. Web servers, load balancers, email servers, VPN endpoints. If a client can’t support TLS 1.2, that client has bigger problems than your website.

Configure TLS 1.3 as the preferred version. Use Mozilla’s SSL Configuration Generator for battle-tested configurations for Apache, Nginx, HAProxy, and others.

Enforce forward secrecy. Only allow cipher suites with ECDHE key exchange. Remove any static RSA cipher suites from your configuration.

Enable HSTS. Add the Strict-Transport-Security header with a long max-age and includeSubDomains. Submit your domain to the HSTS preload list for maximum protection.

Test your configuration. Run SSL Labs Server Test on every public-facing TLS endpoint. Fix anything below an A rating. Check quarterly — configurations can drift.

Monitor certificate validity. Set up alerting for certificate expiration. Automate renewal with ACME/Let’s Encrypt. An expired certificate is an outage and a potential downgrade vector.

Sources & Further Reading