How HTTPS secures a connection before the page loads
HTTPS protects most web traffic. This guide describes in order what happens in the milliseconds before a page loads, from the first packet to the first encrypted request.
The three guarantees HTTPS makes
HTTPS is HTTP over TLS. TLS is the encryption layer that secures modern web requests. TLS 1.3 (RFC 8446, 2018) is the current standard, replacing TLS 1.2 (2008) and the deprecated SSL series. The handshake establishes a shared secret between client and server using public-key cryptography; once established, symmetric encryption protects all subsequent data.
HTTPS provides three separate guarantees, not just encryption. Without all three the connection cannot be considered secure, and each one is defeated by a different kind of attacker.
Confidentiality
ISPs, routers and Wi-Fi snoopers cannot read the payload. After the handshake the bytes look like random noise to anyone who doesn't hold the session key.
Integrity
The data cannot be modified in transit without the modification being detected. Authenticated encryption attaches a tag; flip a single bit of ciphertext and decryption fails.
Authentication
You are talking to the server you meant to reach, not an impostor on the same coffee-shop network or someone holding a forged cert. This relies on PKI, covered in Part 04.
The two kinds of cryptography TLS uses
TLS combines two kinds of cryptography with opposite trade-offs, and uses each only for the job it suits.
Padlock and key
Anyone can snap the padlock shut (encrypt with a public key), but only the person holding the physical key (the private key) can open it. RSA and elliptic-curve variants work this way. The math is expensive, far too slow to stream video through, so TLS uses it only during the handshake to safely agree on a shared secret.
One shared secret
A single key that both sides hold. AES-256 in GCM mode is typical, and it is hardware-accelerated on modern CPUs, fast enough to encrypt gigabits per second per core. Once the handshake hands over the shared secret, all bulk data is symmetric from there on.
TLS = asymmetric math (slow) + symmetric math (fast). The slow math exists only to deliver the key for the fast math, and once that key is in place it isn't used again for the session.
The TLS handshake, one message at a time
Before a single byte of application data is sent, the client and server perform a short, fixed exchange called the TLS handshake. Toggle between the modern version (TLS 1.3) and its predecessor (TLS 1.2) below, and compare the round trips. TLS 1.3 finishes in one; 1.2 needs two. That difference is a large part of why 1.3 exists.
The client announces what it can speak and pre-ships a key share, so the server can derive the shared secret on receipt, which saves a round trip. SNI names the host; ALPN offers application protocols.
How certificates build a chain of trust
The handshake depends on the client verifying the server's certificate. What stops an attacker from handing a browser a fake cert that says "I am yourbank.com"?
The answer is the chain of trust. Every operating system and browser ships with a pre-installed root store holding the keys of a few dozen trusted third parties called Certificate Authorities (DigiCert, Sectigo, GlobalSign, Let's Encrypt and others).
- 01
Domain validation
You construct a Certificate Signing Request containing your public key and send it to a CA. They verify (usually via a file you place on your web server, or a DNS record you create) that you control the domain.
- 02
CA signature
Once validation passes, the CA signs your certificate with its private key, usually through an intermediate certificate that chains up to a root. Anyone who has the CA's corresponding public key can verify the signature.
- 03
Client verification
When a browser connects, your server presents the signed certificate. The browser checks the signature, finds the matching root in its root store, and verifies the chain. If it verifies, the browser trusts the certificate. If not, the user sees a full-page certificate warning.
What perfect forward secrecy protects
The classic RSA key exchange had a serious weakness: if an attacker recorded months of your encrypted traffic and later stole your server's private key, they could decrypt every recorded session.
The fix is called Perfect Forward Secrecy, implemented in modern TLS via Ephemeral Elliptic-Curve Diffie-Hellman (ECDHE). Instead of the server's private key being used to decrypt a shared secret, the client and server dynamically compute a brand new ephemeral key pair for every session. Diffie-Hellman lets two parties exchange public values and independently arrive at the same shared secret, without the secret itself ever crossing the wire.
The server's long-lived private key is used only for authentication. It signs a message during the handshake to prove identity, but it is not involved in deriving the encryption keys. If the server is compromised tomorrow, yesterday's recorded traffic stays secure.
What TLS 1.3 changed: lighter and faster
Finalized in 2018 as RFC 8446, TLS 1.3 was a substantial rewrite. It removed legacy features, hardened the defaults and cut the handshake from two round trips to one.
Removing legacy ciphers
TLS 1.2 kept dozens of insecure ciphers (RC4, DES, SHA-1) for backward compatibility. Attackers exploited this with downgrade attacks, tricking the negotiation into picking broken crypto. TLS 1.3 deleted them and keeps five AEAD cipher suites.
1-RTT by default
With only a few ciphers and groups to pick from, the client can guess what the server will accept and include its DH key share in the very first packet. The server replies with its share, its certificate and Finished in one flight, so the handshake takes half the round trips of TLS 1.2.
Zero round trips on resumption
TLS 1.3 also added 0-RTT resumption. If a user has visited recently, the client and server hold a resumption ticket, and on the next visit the browser can encrypt the GET request and send it alongside the ClientHello. On reconnects, the latency is then close to that of unencrypted HTTP.
SNI and ALPN: two ClientHello extensions
The ClientHello carries more than ciphers and random values. Two small extensions matter here: one selects the certificate, the other selects the protocol that will run on top.
Choosing the certificate
One IP can host hundreds of sites. Before the server can choose which certificate to present, it needs to know which hostname the client is trying to reach, because a cert is pinned to a name. SNI puts that hostname in the ClientHello in the clear (pre-handshake, there is no encryption yet), so routers and load balancers can also dispatch to the right backend without decrypting anything.
Choosing the application protocol
The client advertises which application protocols it supports: h2 for HTTP/2, http/1.1 for the classic, or both in preference order. The server picks one, echoes it back in the ServerHello, and that choice is locked in for the life of the connection. There is no upgrade step and no second round trip to discover HTTP/2 support. ALPN is also what HTTP/3 uses to be pointed at (via Alt-Svc and the h3 token) once QUIC is in play.
SNI has a privacy cost: because it's sent in cleartext, a passive observer knows which site you're visiting even though they can't read what you do there. Encrypted Client Hello (ECH), the successor to ESNI, wraps the entire ClientHello (including SNI) in a second layer of encryption using a public key the front-end publishes in DNS. It is now standardised as RFC 9849, and Cloudflare and Firefox already ship it. SNI, its routing tricks, and ECH get the full treatment in the dedicated SNI guide.
How to harden the chain of trust
PKI on its own has gaps. Certificates get compromised, attackers can strip HTTPS on the first visit before HSTS takes effect, and CAs occasionally misissue or get tricked. Three mechanisms close most of these gaps.
The server proves the cert isn’t revoked
When a cert is compromised, the CA revokes it, but the browser still has to find out. The simple approach is an OCSP query to the CA at connection time, which adds latency and leaks your browsing history to the CA. Stapling reverses this: the server periodically fetches a fresh, signed OCSP response from the CA and attaches (staples) it to its own handshake. The browser verifies the short-lived signature without contacting the CA, which is faster and keeps browsing history private.
Forcing HTTPS on every future visit
An Strict-Transport-Security header tells the browser: "for the next year, refuse to talk to me over HTTP, even if the user types http:// or clicks a plaintext link." Once cached, downgrade attacks are impossible for that period. The HSTS preload list, shipped with every browser, closes the first-visit gap for domains that opt in.
Every certificate is publicly logged
Certificate Transparency requires every publicly-trusted cert to be submitted to tamper-evident append-only logs. The CA receives a Signed Certificate Timestamp in return, which is embedded in the cert itself. Browsers refuse certs without SCTs. If someone obtains a rogue cert for your domain, you (or a monitor such as crt.sh) can spot it in the logs within minutes.
Inside a ClientHello, field by field
The handshake from Part 02 is a sequence of TLS records. Each record is at most 214 bytes (16 KiB), wraps a typed payload (handshake, application data, alert, change cipher spec), and carries a 5-byte header. The first record a client sends is a ClientHello, which lists everything the client supports.
# TLS RECORD HEADER (5 bytes) 16 03 01 00 a3 # type=Handshake(22), version=TLS1.0(legacy), length=0x00a3 # HANDSHAKE HEADER (4 bytes) 01 00 00 9f # msg_type=ClientHello(1), length=0x00009f # CLIENT HELLO BODY 03 03 # legacy_version = TLS1.2 (0x0303) — 1.3 negotiates via extension 54 7c…32 random bytes… # ClientRandom (32B) — feeds the key schedule 00 # legacy_session_id (empty in 1.3) 00 06 # cipher_suites length = 6 13 01 13 02 13 03 # TLS_AES_128_GCM_SHA256, AES_256_GCM, CHACHA20_POLY1305 01 00 # compression_methods = [null] — never negotiated in TLS 1.3 00 6e # extensions length = 110 bytes 00 00 00 0d … # server_name (SNI): "api.example.com" 00 0a 00 04 00 1d 00 17 # supported_groups: x25519, secp256r1 00 0d 00 0a … # signature_algorithms: ed25519, rsa_pss_rsae_sha256, ecdsa_secp256r1_sha256 00 33 00 26 … # key_share: x25519 public key (32 bytes) 00 2d 00 02 01 01 # psk_key_exchange_modes: psk_dhe_ke 00 2b 00 03 02 03 04 # supported_versions: TLS 1.3 (0x0304) 00 10 00 0e … # ALPN: h2, http/1.1
The body is a fixed prologue plus a free-form list of extensions. TLS 1.3 freezes the prologue (legacy fields are kept identical for middlebox compatibility) and moves all real negotiation into extensions: the version, the key exchange group, the public key, the SNI hostname and the ALPN protocol list. The server only echoes what it accepts, and ignores any extension it doesn't recognise.
Telling the server which certificate to send
Many sites share one IP. Without Server Name Indication the server wouldn't know which certificate to present. SNI travels in the clear in the ClientHello, which is why Encrypted Client Hello (ECH, RFC 9849) wraps the inner ClientHello inside an outer one whose SNI names only the frontend provider.
Guessing the key group to save a round trip
In TLS 1.2 the client first asked which group the server supported, then sent the public key. TLS 1.3 fuses both: the client guesses (usually X25519) and includes a key share for it. If the server agrees, the handshake completes in 1-RTT. If the server wants a different group, it replies with a HelloRetryRequest and the client sends another ClientHello, which costs one extra round trip.
Agreeing on HTTP/2 vs HTTP/1.1 in the handshake
Application-Layer Protocol Negotiation chooses between h2, h3, and http/1.1 inside the same handshake. There is no second round trip after TLS finishes. ALPN is also how WebRTC (webrtc) and gRPC (h2) avoid sniffing.
openssl s_client -connect example.com:443 -servername example.com -tls1_3 -trace dumps every record in this format, and the -trace flag labels each field. For a live Wireshark filter, use tshark with tls.handshake.
The five cipher suites TLS 1.3 kept
TLS 1.2 had 37 standard cipher suites and over three hundred legacy ones: RC4, 3DES, MD5, RSA key exchange, anonymous DH. Misconfiguration was common. TLS 1.3 cut the menu to five, all AEAD, all forward-secret. Key exchange, signature and certificate type moved to extensions, where each can change without touching the rest.
| Suite | Cipher | Hash (HKDF) | Where it shines |
|---|---|---|---|
| TLS_AES_128_GCM_SHA256 | AES-128-GCM | SHA-256 | Default. Fast on hardware with AES-NI. |
| TLS_AES_256_GCM_SHA384 | AES-256-GCM | SHA-384 | Compliance ceilings (NSA Suite B, FIPS). |
| TLS_CHACHA20_POLY1305_SHA256 | ChaCha20-Poly1305 | SHA-256 | Mobile / no AES-NI. Constant-time, no timing attacks. |
| TLS_AES_128_CCM_SHA256 | AES-128-CCM | SHA-256 | IoT / DTLS where GCM hardware isn't available. |
| TLS_AES_128_CCM_8_SHA256 | AES-128-CCM-8 | SHA-256 | Constrained devices. 8-byte tag instead of 16. |
Always (EC)DHE.
Every TLS 1.3 session uses ephemeral Diffie-Hellman for the key. RSA key transport is gone. The supported_groups extension lists curves: x25519 (default; 32-byte keys, fast, formally analysed), secp256r1 / secp384r1 (NIST curves; required by FIPS), x448 (larger curve, higher security level). Ephemeral keys mean a stolen long-term private key cannot decrypt past traffic: perfect forward secrecy is on by default.
Certificate and signature
The server signs the transcript with the private key matching its certificate. signature_algorithms negotiates the algorithm: ed25519 (modern, fast, deterministic), ecdsa_secp256r1_sha256 (most common ECDSA), rsa_pss_rsae_sha256 (RSA, but properly padded). MD5 and SHA-1 signatures are flatly forbidden: past attacks proved a downgrade existed in TLS 1.2.
Pre-1.3 TLS used MAC-then-encrypt as a separate composition, and a series of attacks (Lucky13, BEAST, POODLE) lived in that gap. AEAD ciphers do encryption and authentication in one operation: every byte of ciphertext is bound to its position and to the associated plaintext header. There is no padding oracle to leak through, no MAC truncation to exploit. The 1.3 cipher list is short on purpose.
Inspecting TLS from the command line
Most TLS production failures are a wrong certificate chain, an expired cert, a name mismatch, a protocol downgrade or SNI not configured. Five tools cover almost every diagnosis from the terminal.
- 01
Inspect the chain. openssl s_client
openssl s_client -connect example.com:443 -servername example.com -showcerts. Prints the entire certificate chain the server sent, in order. Use -tls1_3 to force the version, -status to also fetch the OCSP staple, and < /dev/null to close immediately after the handshake instead of hanging on stdin.
- 02
Decode a single cert. openssl x509
openssl x509 -in cert.pem -noout -text dumps the certificate as readable text: Subject, Issuer, validity window, Subject Alternative Names, key algorithm, fingerprint, embedded SCTs. -checkend 86400 is useful for monitoring because it exits non-zero if the cert is within 24 hours of expiry.
- 03
Walk the connection. curl -v
curl -v https://example.com shows the resolved IP, the cipher suite, the negotiated ALPN protocol, the chain verification result, and the response headers. Add --resolve example.com:443:1.2.3.4 to test a specific origin behind a load balancer, and --cacert to point at a custom root for self-signed environments.
- 04
Verify against a public scan. testssl.sh
testssl.sh --severity HIGH https://example.com runs a full audit: protocol versions, cipher suites, vulnerability scans (Heartbleed, ROBOT, Logjam), HSTS posture, CT log presence. It is open source and runs locally. Pairs with ssllabs.com/ssltest for a public report card.
- 05
Watch the wire. tshark / wireshark
tshark -i any -f "host example.com and port 443" -O tls filters the live traffic and parses every TLS record. To decrypt your own connections, set SSLKEYLOGFILE=/tmp/keys.log in the environment of the originating browser or curl; Wireshark reads the keylog and shows you the application data in plaintext.
SSL_ERROR_NO_CYPHER_OVERLAP: the client's cipher list and the server's don't intersect. Usually a TLS 1.3-only server talking to an ancient client.
unable to get local issuer certificate. The server didn't send the intermediate; install the full chain, not just the leaf.
subjectAltName: no name matching. The cert's SANs don't include the requested host. CN-only certs stopped being trusted in browsers years ago.
certificate expired. The most common alert of all. Set up a x509 -checkend monitor.
Modern TLS in production: Let's Encrypt, mTLS, post-quantum
What production TLS looks like in practice.
Let's Encrypt is the default for most sites. Free, automated, 90-day certificates via the ACME protocol have helped drive HTTPS to roughly 95% of page loads (Google's HTTPS transparency report). Tools such as certbot, acme.sh and Caddy's automatic HTTPS make deployment easy. Paid certificates remain mainly for organisation-validated (OV) and extended-validation (EV) types, which browsers no longer visually distinguish.
mTLS for service-to-service. In mutual TLS both sides present certificates, and it is the dominant pattern in modern service meshes. Istio, Linkerd and AWS App Mesh issue and rotate workload certificates automatically (typically via SPIFFE-style identity). Certificate management used to be a heavy operational cost, and service mesh automation made mTLS cheap to run.
Post-quantum readiness. Quantum computers running Shor's algorithm would break RSA and ECDH at scale. NIST standardised the first post-quantum KEM as ML-KEM (FIPS 203, née Kyber). Cloudflare and Google ship hybrid TLS handshakes (X25519 + ML-KEM) in production; the long tail of embedded and legacy clients means the full transition will take around a decade.
HSTS preload list. Over 100,000 domains are on the browser-bundled HSTS preload list, so browsers refuse HTTP to them even on the first visit. The one-time submission is worth making for any production site.
Certificate Transparency. Every cert from a public CA must appear in a public CT log within seconds of issuance. crt.sh lets you search them; production teams use this to detect rogue certificates issued for their domains.
Ten years ago, mostly banks enforced HTTPS. Certificates were expensive, handshakes were slow, and most of the web stayed plaintext. Today Let's Encrypt issues certificates for free in seconds, AES-NI makes bulk encryption cheap, and browsers only speak HTTP/2 and HTTP/3 over TLS. HTTPS is now the default transport for almost everything you load.
Three quick checks
Test what you just read about the TLS handshake.
Pick an answer for each. Every answer, right or wrong, shows a short explanation, and there is no scoring.
Further
reading
- Cloudflare LearningWhat happens in a TLS handshake?The same ground from a CDN's point of view, with packet diagrams.
- IETF · RFC 8446The Transport Layer Security Protocol · Version 1.3The spec itself. Dense, but every byte of the handshake is defined here.
- Let's EncryptHow It Works · ACME domain validationThe automation that turned certificates from a $500/year purchase into something a cron job can renew.
- MDNConnection management in HTTP/1.xHow HTTP sits on top of TLS on top of TCP. Keep-alive, pipelining, parallel connections.
- Googlecertificate.transparency.devThe why and how of CT logs, plus crt.sh for live auditing.
- IETF · RFC 5280X.509 Certificate & CRL ProfileThe format of every public certificate: Subject, Issuer, SANs, basic constraints and key usage. Pair with Part 09's wire format.
- Cloudflare blogWhy TLS 1.3 isn't in browsers yet, and the path to deploymentA retrospective on the middlebox compatibility workarounds that shaped Part 09's "legacy fields are kept identical" line.
- Ivan RistićBulletproof TLS GuideA reference book for operating TLS in production, with configuration matrices, weakness catalogs and deprecation timelines.
- testssl.shA complete TLS auditor in a shell scriptThe tool from Part 11. Its README works as a catalog of known TLS attacks and the tests that catch them.
- IETF · RFC 6962Certificate TransparencyThe Merkle-tree append-only log behind Part 08. Short, and it explains why every public cert is now publicly auditable.
- IETF · RFC 9460SVCB and HTTPS DNS Resource RecordsHow Encrypted Client Hello (ECH) is bootstrapped. The DNS record that hides the SNI mentioned in Part 09.