When your browser connects to a website, data travels through networks you don't control. Routers, ISPs, cables, wireless access points. Any of these could, in principle, be operated by someone who can see or modify your traffic.
The obvious response is encryption. Encrypt the data before sending it, and an observer sees only ciphertext. But encryption alone doesn't solve the harder problem.
Before Alice can encrypt anything for Bob, she needs Bob's public key. And if someone is sitting between Alice and Bob, they can intercept that key exchange.
Alice → "Give me your public key"
↓
Attacker intercepts
↓
Sends attacker's key instead
↓
Alice encrypts to the attacker's key,
believing she's communicating with Bob
Alice now has an "encrypted" connection. But she's encrypting to the wrong person. The attacker decrypts her messages, reads or modifies them, re-encrypts to Bob's actual key, and forwards them. Both sides think they have a private connection. Neither does.
This is the core problem. Encryption protects communication only if you know whose key you're encrypting to. The interesting question isn't whether traffic can be encrypted. It's how Alice can verify that the key she received actually belongs to Bob.
A Public Key Doesn't Come with Identity
Public-key cryptography gives us a useful primitive: a key pair where one key can sign and the other can verify. As covered in the digital signatures article, a signature over some data proves that the signer possessed the corresponding private key at signing time.
But a public key by itself says nothing about who created it. Anyone can generate a key pair. The fact that you have a key labeled "belongs to example.com" doesn't make it true. What's needed is a trustworthy mechanism for binding a public key to an identity.
This is what a digital certificate does.
What a Certificate Is
A TLS certificate is a signed document. It contains a domain name, the server's public key, validity information, and the issuer. Critically, it includes a digital signature from a Certificate Authority that vouches for the binding between that domain and that public key.
Domain identity
+
Server public key
↓
Certificate
↓
Signed by Certificate Authority
The CA's signature is what allows a client to verify that a trusted authority has attested to the binding between that domain identity and public key. Because the client can verify the CA's signature using the CA's public key, which it already has, a valid signature over the certificate means a trusted authority stands behind the claim that this public key belongs to this domain. Operating systems and browsers ship with a trust store: a set of root CA certificates that are considered trustworthy by default. If a certificate chains up to one of those roots, and the signature is valid, the client can trust that the domain-to-key binding has been attested by a trusted authority.
If an attacker creates a certificate for a target domain without the corresponding private key, or gets a certificate signed by a CA that clients don't trust, the verification fails. The browser flags the connection.
Attacker's certificate
↓
Not signed by a trusted CA for that domain
↓
Verification fails
↓
Browser warns / connection rejected
The TLS Handshake
Knowing the theory is one thing. Seeing how it plays out during a connection is another. Here's a simplified TLS 1.3 handshake:
Client Server
ClientHello ──────────────────────→
←──────────────────── ServerHello
←──────────────────── Certificate
←──────────────────── CertificateVerify
←──────────────────── Finished
Finished ──────────────────────→
Encrypted application data
←─────────────────────────→
ClientHello: The client sends its supported protocol versions, cipher suites, and key-share information for the key exchange.
ServerHello: The server selects the protocol version and cipher suite, and responds with its own key-share contribution. At this point, both sides have enough information to derive shared secrets. The key exchange happens through a scheme like ECDHE, where both sides contribute values that allow them to compute a shared secret independently without ever transmitting the secret itself.
Certificate: The server sends its certificate chain so the client can authenticate the server's identity. The client validates the chain against its trust store, checks the certificate's validity period, and verifies that the domain name in the certificate matches the server being connected to.
CertificateVerify: This is the step most explanations skip, and it's important. The certificate proves that some trusted authority bound a public key to a domain. But it doesn't prove that the server currently possesses the corresponding private key. An attacker who obtained a copy of someone's certificate but not their private key could present that certificate.
CertificateVerify closes this gap. The server signs the handshake transcript so far using its private key. The client verifies this signature against the public key in the certificate. A valid signature proves that whoever is running this server possesses the private key, not just the certificate.
Finished: Both sides send a Finished message that covers the entire handshake transcript. This verifies that neither side's view of the handshake has been tampered with, and that both have derived the same session keys.
Why Symmetric Encryption Handles the Data
Public-key operations are computationally expensive. Encrypting every byte of application data with asymmetric cryptography would be impractically slow for most connections.
The handshake solves this elegantly. The key exchange produces shared secret material from which the connection derives symmetric session keys. Those keys are used for all subsequent application data.
Handshake key exchange
↓
Shared secret
↓
Symmetric session keys
↓
Fast symmetric encryption
↓
Application data
Public-key cryptography does the authentication and key agreement. Symmetric cryptography does the heavy lifting on the actual data. This separation is a deliberate design choice.
Why the MITM Now Fails
Return to the original attack. An attacker sitting between Alice and the server wants to substitute their own key.
Without TLS, they can. Alice receives the attacker's key, encrypts to it, and the attacker decrypts the traffic.
With TLS:
Alice
↓
Receives certificate
↓
Verifies chain against trust store
↓
Confirms domain matches
↓
Verifies CertificateVerify signature
↓
Proves server holds the private key
↓
Session established
For the attacker to impersonate the server, they'd need a certificate for the target domain that chains to a trusted CA, and the private key corresponding to the public key in that certificate. A fraudulent certificate from a CA that clients don't trust fails at the verification step. A valid certificate without the matching private key fails at CertificateVerify.
The MITM position doesn't help anymore. Observing the traffic reveals ciphertext encrypted under session keys the attacker doesn't have. Injecting their own certificate fails certificate verification. The attacker is stuck.
What TLS Doesn't Cover
TLS protects data in transit between authenticated endpoints. It doesn't protect against a compromised server, malicious code already running on the client, stolen private keys, or data after it's been decrypted at the destination. A padlock in the browser means the connection to that server is authenticated and encrypted. It says nothing about what the server does with your data once it arrives.
TLS doesn't solve the MITM problem by adding encryption. It solves a harder problem first: establishing who you're actually communicating with before that encryption can be trusted.
Certificates bind identities to public keys. Certificate Authorities create a chain of trust the client can verify. The TLS handshake authenticates the server, proves private-key possession, and negotiates shared secrets through key exchange. Symmetric encryption protects the connection efficiently from there.
That's what happens in the moment between typing a URL and the page loading. It's fast enough to feel instantaneous and careful enough that an attacker sitting on the network between you and the server can't impersonate either side.
Top comments (0)