Demystify HTTPS — understand TLS handshakes, certificates, public-key cryptography, and why that padlock in your browser matters for developers.
Every developer uses HTTPS every day. Few understand what's happening behind that padlock icon. This guide explains TLS 1.3 in plain language — covering the cryptography that protects every web request you make.
Plain HTTP transmits everything in cleartext. Anyone on the same network (coffee shop WiFi, ISP, compromised router) can:
HTTPS adds a TLS (Transport Layer Security) layer between HTTP and TCP, solving all of these.
Client Server
| |
|── ClientHello ──────────────>| (supported ciphers, random, key share)
| |
|<─ ServerHello ───────────────| (chosen cipher, random, key share)
|<─ Certificate ───────────────| (server's TLS certificate)
|<─ CertificateVerify ─────────| (signature proving private key ownership)
|<─ Finished ──────────────────|
| |
|── Finished ─────────────────>|
|── [Encrypted HTTP Request] ->|
|<─ [Encrypted HTTP Response]--|
TLS 1.3 requires only 1 round-trip to complete the handshake (vs 2 in TLS 1.2). With session resumption (0-RTT), repeat connections can skip the handshake entirely.
TLS 1.3 uses Diffie-Hellman key exchange (specifically X25519 or P-256 elliptic curves).
The mathematical magic: two parties can independently compute the same shared secret without ever transmitting it.
Alice picks private key: a
Bob picks private key: b
Both agree on public: G
Alice sends: A = G^a mod p
Bob sends: B = G^b mod p
Alice computes: B^a mod p = G^(ab) mod p ✓
Bob computes: A^b mod p = G^(ab) mod p ✓
Both have the same secret G^(ab) — an eavesdropper who sees A and B
cannot compute G^(ab) without solving the discrete logarithm problem.
A TLS certificate is a signed document containing:
Your browser trusts certificates signed by CAs in its built-in trust store (~150 CAs). The CA signs the certificate with its private key; your browser verifies with the CA's public key.
# View a certificate
openssl s_client -connect heolab.com:443 -showcerts
# Check certificate expiry
openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Generate a self-signed certificate (for local dev)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Before Let's Encrypt (2015), TLS certificates cost $100–$300/year. Now they're free and automatically renewed:
# Install certbot and get a certificate
sudo certbot --nginx -d yourdomain.com
# Auto-renewal (add to cron)
0 12 * * * /usr/bin/certbot renew --quiet
Vercel, Netlify, and Cloudflare provision certificates automatically — you don't need to manage them.
TLS 1.3 mandates Perfect Forward Secrecy (PFS): a new ephemeral key pair is generated for every session. Even if an attacker records all your encrypted traffic and later steals the server's private key, they cannot decrypt past sessions.
This is why TLS 1.3 removed RSA key exchange (which didn't have PFS) — only Diffie-Hellman variants are allowed.
Prevent the first request from going over HTTP:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
After a browser sees this header once, it will only use HTTPS for that domain for the next year — even if you type http:// in the address bar.