EncryptCodecencryptcodec
Blog/Security
SecurityMarch 15, 2026 · 9 min read

How HTTPS Actually Works — A Developer's Guide to TLS

You've shipped a feature behind HTTPS and called it secure. Then a pentest comes back flagging TLS 1.0 support, weak cipher suites, or a misconfigured certificate chain — and you realise you've been treating HTTPS as a checkbox, not a protocol you understand. This guide fixes that.

The Problem with "Just Use HTTPS"

HTTPS isn't a single thing. It's HTTP layered over TLS (Transport Layer Security), and TLS itself is a negotiation — the server and client agree on algorithms, exchange keys, verify identities, and only then start sending data. Every step in that process has options, and some of those options are catastrophically weak.

A server that supports TLS 1.0, RC4 ciphers, or SHA-1 signed certificates is "using HTTPS" in the same way a screen door is "using a lock."


The TLS Handshake, Step by Step

When your browser connects to https://example.com, here's what actually happens before a single byte of HTTP is transmitted:

1. ClientHello

The client sends:

  • TLS version(s) it supports
  • A random 32-byte nonce (client_random)
  • A list of supported cipher suites (e.g., TLS_AES_256_GCM_SHA384)
  • Supported extensions (SNI, ALPN, etc.)

SNI (Server Name Indication) is how a single IP address can serve multiple HTTPS domains. The hostname is sent in plaintext here — which is why SNI leaks your destination even over HTTPS without ECH (Encrypted Client Hello).

2. ServerHello

The server responds with:

  • The TLS version selected
  • Its own random nonce (server_random)
  • The chosen cipher suite
  • Its certificate (or certificate chain)

3. Certificate Verification

The client verifies:

  1. The cert is signed by a trusted CA (following the chain up to a root)
  2. The hostname matches the cert's CN or SAN fields
  3. The cert hasn't expired
  4. The cert hasn't been revoked (via OCSP or CRL)

Gotcha: Intermediate certificates must be bundled with the server cert. Desktop browsers silently fetch missing intermediates via AIA (Authority Information Access). Mobile clients and most HTTP clients in Node.js, Java, and Python do not. A broken chain that "works in Chrome" will cause CERTIFICATE_VERIFY_FAILED in production API calls and cause you to spend two hours questioning your sanity.

4. Key Exchange

This is where the session key gets established. In TLS 1.2, this is typically RSA or ECDHE. In TLS 1.3, it's always ECDHE (Elliptic Curve Diffie-Hellman Ephemeral).

With ECDHE:

  • Both sides contribute to the key material
  • The final session key is never transmitted over the wire
  • Each session uses a fresh key pair — this is forward secrecy

Forward secrecy means that even if the server's private key is stolen later, past sessions can't be decrypted. With RSA key exchange (old TLS 1.2), all past traffic is retroactively decryptable if the private key is compromised.

5. Finished

Both sides compute a MAC over the full handshake transcript and verify they match. Any tampering during the handshake would be detected here.

TLS 1.3 Handshake

Press Play to walk through the TLS 1.3 handshake


Cipher Suites: Where Configuration Goes Wrong

A cipher suite defines the algorithms used for each part of the connection. Example:

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Breaking this down:

  • ECDHE_RSA — key exchange (ECDHE) + certificate type (RSA)
  • AES_256_GCM — symmetric encryption algorithm and mode
  • SHA384 — MAC/HMAC for integrity

Avoid:

  • RC4 — broken, known keystream biases
  • 3DES / DES — SWEET32 vulnerability, too slow
  • CBC mode suites in TLS 1.2 — BEAST, Lucky13 attacks
  • NULL encryption suites — yes, these exist and some servers enable them
  • EXPORT suites — backdoored by design (FREAK attack)

Use:

  • TLS_AES_128_GCM_SHA256 or TLS_AES_256_GCM_SHA384 (TLS 1.3 only)
  • TLS_CHACHA20_POLY1305_SHA256 — better performance on mobile/ARM

In TLS 1.3, cipher suite selection is drastically simplified. There are only five options, all strong. This is the right answer to the question "which cipher suites should I configure?" — upgrade to TLS 1.3 and let the spec make the decision for you.


Certificates: The Chain of Trust

Your certificate proves to clients that you are who you say you are. The trust model works like this:

  1. Root CA — Pre-installed in OS/browser trust stores (DigiCert, Let's Encrypt ISRG Root, etc.)
  2. Intermediate CA — Signed by the root, used for day-to-day issuance
  3. Leaf certificate — Your domain cert, signed by the intermediate

Your server must send the leaf cert plus all intermediate certs. Not the root (that comes from the trust store).

Certificate Fields That Actually Matter

  • SAN (Subject Alternative Name) — The actual list of domains the cert covers. CN is legacy and ignored by modern clients.
  • Not Before / Not After — Expiry. Automate rotation. Let's Encrypt certs expire in 90 days by design to force automation.
  • Key Usage / Extended Key Usage — Cert must have serverAuth for HTTPS. Using a code-signing cert for TLS is a misconfiguration that some servers will silently accept and clients will reject.

Symmetric Encryption: The Actual Data Transfer

Once the handshake completes, both sides have the same session key (derived via HKDF from the handshake key material). All HTTP data is encrypted with AES-GCM or ChaCha20-Poly1305.

These are AEAD (Authenticated Encryption with Associated Data) ciphers — they provide confidentiality and integrity in one primitive. Every record includes an authentication tag; tampering with the ciphertext causes decryption to fail.

Record size matters here: TLS splits data into records of up to 16KB. An attacker watching traffic can still infer things from record sizes and timing even when content is encrypted. This is why HTTPS doesn't fully prevent traffic analysis.


Practical Code: Verifying TLS Configuration

const https = require('https');
const tls = require('tls');

// Check TLS details for a given host
const socket = tls.connect(443, 'example.com', { servername: 'example.com' }, () => {
const cert = socket.getPeerCertificate(true);
const protocol = socket.getProtocol(); // e.g., 'TLSv1.3'
const cipher = socket.getCipher();     // { name, version }

console.log('Protocol:', protocol);
console.log('Cipher:', cipher.name);
console.log('Cert subject:', cert.subject);
console.log('Cert valid until:', cert.valid_to);
console.log('Chain verified:', socket.authorized);

if (!socket.authorized) {
  console.error('Chain error:', socket.authorizationError);
}

socket.destroy();
});

Common Misconfigurations

HSTS preloading is one-way

Once you submit your domain to the HSTS preload list, removing it takes months to propagate. Don't preload until you're certain you'll never need plain HTTP on that domain again.

Mixed content breaks silently in different ways

Active mixed content (scripts, iframes) is blocked. Passive mixed content (images) may load with a warning. Either kills the padlock and can allow partial page hijacking.

Certificate pinning is a maintenance trap

Pinning the server's cert (not the CA) means a cert rotation breaks your mobile app until users update. Pin the CA or intermediate, set a backup pin, and have a rotation plan before you ship.

TLS termination at the load balancer means internal traffic is unencrypted

Common in Kubernetes setups. If your internal network is compromised, all traffic between services is plaintext. Use mutual TLS (mTLS) between services if this is a concern.


Run testssl.sh or SSL Labs against your domains right now. Look for: TLS 1.0/1.1 support, CBC cipher suites, missing HSTS headers, and incomplete certificate chains. Fix in that order. Then enforce TLS 1.2 minimum (TLS 1.3 preferred) in your reverse proxy or load balancer config, disable all cipher suites that don't provide forward secrecy, and automate certificate rotation before you touch anything else.

The padlock doesn't mean you're secure. It means you're encrypted — and only if the configuration behind it is sound.

Share this post

Generate a secure random secret

Free, browser-based — no signup required.

Frequently Asked Questions

Related posts