Backend / Networking / 12_tls_https_certificates.md

TLS, HTTPS, Certificates

Updated 6 interview angles 7 min read source
On this page14
  1. What TLS gives you
  2. TLS 1.3 handshake (1-RTT)
  3. Certificate basics
  4. Certificate types
  5. Let’s Encrypt + ACME
  6. SNI — multiple sites, one IP
  7. mTLS (Mutual TLS)
  8. Cipher suites and PFS
  9. Common cert errors and what they mean
  10. Python TLS gotchas
  11. HSTS — force HTTPS
  12. What gets encrypted, what doesn’t
  13. Common interview confusions
  14. Interview angle

TLS, HTTPS, Certificates

TLS (Transport Layer Security) encrypts a TCP connection. HTTPS = HTTP over TLS. Modern web is TLS 1.2 and 1.3; everything older (SSL 2/3, TLS 1.0/1.1) is deprecated.

What TLS gives you

  1. Confidentiality — observers see ciphertext.
  2. Integrity — tampering is detected.
  3. Authentication — the server proves it’s who the cert says it is. (Mutual TLS authenticates the client too.)

It does not give you:

  • Authorization. TLS proves identity; your app decides what they can do.
  • Hiding metadata fully. The destination IP, port, packet sizes, SNI hostname (in TLS <1.3 without ECH) are visible.

TLS 1.3 handshake (1-RTT)

text
Client  ──ClientHello (key share, suites, SNI)──▶  Server
Client  ◀── ServerHello + {EncryptedExtensions,
            Certificate, CertificateVerify, Finished} ── Server
Client  ──{Finished}──▶  Server
( application data starts; total 1 RTT, 0 RTT for resumption )

Braces mark encrypted messages: in TLS 1.3 everything after ServerHello is encrypted, including the certificate. CertificateVerify is the server’s signature over the handshake, which proves it holds the certificate’s key. A ChangeCipherSpec record may still appear, but only for middlebox compatibility; it carries no meaning in 1.3.

TLS 1.2 took 2 RTTs. TLS 1.3 cut it to 1 (and 0 for session resumption). On a 100ms RTT link, that’s saving 100–200ms before HTTP can even start.

Certificate basics

A certificate is a signed claim: “this public key belongs to api.example.com, signed by [CA], valid from X to Y.” Browsers/OSes ship a list of trusted root CAs (~150). A cert is valid if there’s a chain from it back to one of those roots.

text
[ Root CA cert ]              ← trusted by OS/browser, self-signed
       │ signs
[ Intermediate CA cert ]
       │ signs
[ api.example.com cert ]      ← what your server presents

The server presents the leaf + intermediate(s); the client already trusts the root. Forgetting to include the intermediate is the #1 cert misconfiguration — Chrome may still work (it fetches missing intermediates) but curl and Python’s requests fail.

Certificate types

Type Validates
DV (Domain Validated) you control the domain (HTTP/DNS challenge). Let’s Encrypt is DV.
OV (Organization Validated) DV + manual check that org exists
EV (Extended Validation) OV + extra paperwork. Used to show green-bar in browsers; browsers stopped highlighting it.
Wildcard *.example.com — covers any single-level subdomain
SAN (Subject Alternative Name) one cert covers multiple specific names

For 99% of services, a free DV cert from Let’s Encrypt is fine. EV is largely vestigial.

Let’s Encrypt + ACME

Let’s Encrypt issues free DV certs, currently valid for 90 days. The ACME protocol automates issuance and renewal:

  1. Client (Certbot, acme.sh, Caddy built-in) generates a key and CSR.
  2. Tells Let’s Encrypt “I want a cert for example.com.”
  3. Let’s Encrypt challenges: prove you own it.
    • HTTP-01: serve a token at http://example.com/.well-known/acme-challenge/<token>.
    • DNS-01: create a TXT record _acme-challenge.example.com.
    • TLS-ALPN-01: rare, used when you can’t open port 80.
  4. Let’s Encrypt fetches/queries the proof.
  5. Cert issued. Renewal runs automatically, usually when a third of the lifetime remains; ACME Renewal Information (ARI) lets the CA tell the client when to renew, for example ahead of a mass revocation.

Lifetimes are shrinking for every CA: under CA/Browser Forum ballot SC-081 the maximum public TLS certificate validity is 200 days from 2026-03-15, 100 days from 2027-03-15 and 47 days from 2029-03-15. Manual renewal stops being an option. Let’s Encrypt also shut down its OCSP service on 2025-08-06; revocation is published through CRLs.

Caddy and Traefik do this transparently. nginx + certbot is the manual standard. AWS ACM does it for AWS LBs (free, auto-renewed, but only usable on AWS resources).

SNI — multiple sites, one IP

Server Name Indication is a TLS extension where the client sends the hostname during the handshake so the server can pick the right cert. Without SNI, one IP could only host one HTTPS cert.

In TLS 1.2, SNI is plaintext (observers see which site you’re visiting). TLS 1.3 + ECH (Encrypted Client Hello) hides it. ECH is rolling out; Cloudflare supports it server-side, browsers gradually.

mTLS (Mutual TLS)

Server presents a cert; client also presents a cert. Both validate each other.

Use cases:

  • Service-to-service inside a mesh (Istio/Linkerd auto-issue and rotate).
  • High-security APIs (banking, government).
  • Replacing API keys with cryptographic identity.

In Python:

python
import httpx
client = httpx.Client(cert=("client.crt", "client.key"), verify="ca.crt")
client.get("https://api.example.com/")

Cost: cert distribution and rotation is operationally heavy — service meshes exist mostly to make this manageable.

Cipher suites and PFS

A cipher suite specifies key exchange + bulk encryption + MAC. TLS 1.3 stripped this down — only AEAD ciphers remain (AES-GCM, ChaCha20-Poly1305) and key exchange is always (EC)DHE for forward secrecy.

Forward secrecy means a future leak of the server’s long-term key doesn’t decrypt past traffic — each session uses an ephemeral DH key that’s discarded. Important for compliance and for resisting later attacks.

Common cert errors and what they mean

Error Meaning
CERT_HAS_EXPIRED cert past notAfter. Renew.
UNABLE_TO_VERIFY_LEAF_SIGNATURE missing intermediate cert in the chain
HOSTNAME_MISMATCH cert is for foo.com, you connected to bar.com
CERT_AUTHORITY_INVALID root CA not in client’s trust store (self-signed; or CA you didn’t add)
SSL_ERROR_NO_CYPHER_OVERLAP client and server agreed on no cipher; usually too old TLS version on one side

Python TLS gotchas

python
import requests
# disables validation — DON'T in prod
requests.get("https://self-signed.example/", verify=False)
# use a private CA bundle
requests.get("https://api.example/", verify="/path/to/ca.crt")
  • requests ships with certifi (Mozilla CA bundle). On corp networks with MITM proxies, point it at the corporate CA bundle via REQUESTS_CA_BUNDLE env var.
  • urllib3.disable_warnings(InsecureRequestWarning) silences the noise but leaves the security hole. Don’t.
  • ssl.create_default_context() is the right starting point for raw socket TLS.
  • Python’s ssl module has required TLS 1.2 as the minimum by default since 3.10; set minimum_version explicitly only if you must document it or raise it to 1.3.

HSTS — force HTTPS

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

Tells the browser “always use HTTPS for this domain for the next year.” Prevents downgrade attacks. preload opts into the browser’s built-in list (irreversible — think before adding).

What gets encrypted, what doesn’t

Encrypted: HTTP request line, headers, body. Cookies, auth tokens. Whatever’s in the TLS payload.

Visible to observers: source/destination IPs and ports, packet sizes and timing, SNI hostname (without ECH), the fact that you connected.

So TLS hides what you’re saying, but a network observer still knows you talked to api.example.com (and roughly how much). For metadata privacy you need Tor or similar.

Common interview confusions

  • “SSL is the same as TLS.” — SSL 1/2/3 are the historical predecessors; TLS 1.0+ is the modern protocol. People still say “SSL” loosely. Correct vocabulary: TLS.
  • “HTTPS encrypts the URL.” — encrypts the path and query (those are inside the HTTP request). Doesn’t encrypt the destination IP/port or the SNI hostname.
  • “A wildcard cert *.example.com covers example.com.” — no. Wildcards cover one subdomain level. *.example.com doesn’t match example.com itself or a.b.example.com. Use a SAN cert with both names.
  • “TLS proves the server is the right company.” — DV proves they control the domain, nothing more. EV/OV add organization checks. Most attacks don’t need to forge a cert; they redirect DNS or phish.

Interview angle 6

  • “What does TLS provide?” — confidentiality, integrity, server authentication (and client auth in mTLS). Not authorization, not metadata privacy.
  • “Walk through the TLS 1.3 handshake.” — ClientHello (with key share, SNI, cipher list) → ServerHello + cert + Finished → Client Finished + app data. 1 RTT, 0 RTT for resumption.
  • “What’s the cert chain and what’s a common misconfiguration?” — leaf → intermediate → root; root pre-trusted by OS/browser. Common miss: server doesn’t include intermediates, browsers fetch them but curl / requests fail with unable to verify leaf signature.
  • “What’s mTLS and when do you use it?” — both sides present certs. Service-to-service inside a mesh, high-security APIs, replacing static API keys with crypto identity. Cost is cert distribution / rotation — service meshes solve that.
  • “What’s HSTS and what does preload mean?” — header telling browsers to always use HTTPS for this domain. preload adds you to the browser’s hardcoded list — irreversible-ish; opt in with care.
  • “Let’s Encrypt and ACME — how does it work?” — automated DV cert issuance via HTTP-01 or DNS-01 challenge. 90-day certs auto-renewed. Caddy/Traefik do it built-in; nginx pairs with certbot.