HTTPS
02 / 07

TLS & HTTPS

TLS & HTTPS

HTTPS = HTTP + TLS (Transport Layer Security). TLS provides three guarantees: confidentiality (encryption prevents eavesdropping), integrity (tampering is detected), and authentication (you are talking to the right server). Every production site must use HTTPS.

TLS Handshake (TLS 1.3)

# TLS 1.3 Handshake (1-RTT, simplified):
#
# Client → Server: ClientHello
#   - TLS version: 1.3
#   - Cipher suites: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256
#   - Client random (32 bytes)
#   - Key share (Diffie-Hellman public key)
#
# Server → Client: ServerHello + Certificate + Finished
#   - Chosen cipher suite
#   - Server random
#   - Server DH public key
#   - Certificate chain (signed by trusted CA)
#   - Finished MAC (proves handshake integrity)
#
# Client → Server: Finished
#   - Verifies certificate against trusted CA roots
#   - Both sides derive session keys from DH exchange
#   - Encrypted application data begins
#
# 0-RTT (resumption): client can send data with first packet (replay risk)

# Inspect TLS details
openssl s_client -connect example.com:443 -tls1_3 2>&1 | head -40
curl -v https://example.com 2>&1 | grep -E "TLSv|cipher|certificate"

# Check certificate info
openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates -subject -issuer

# Check TLS version support
nmap --script ssl-enum-ciphers -p 443 example.com

# Decode a certificate file
openssl x509 -in cert.pem -text -noout

Certificates: Types & Lifecycle

# Certificate types by validation level:
# DV (Domain Validation) - CA verifies domain ownership only
#   - Let's Encrypt (free), ZeroSSL. Issued in minutes.
#   - OK for most sites and APIs
#
# OV (Organization Validation) - CA verifies org identity
#   - Shows org name in certificate details
#   - Mid-tier price, takes days
#
# EV (Extended Validation) - Rigorous org identity verification
#   - Was shown as green address bar (browsers removed this)
#   - Expensive, takes weeks

# Let's Encrypt with Certbot (free, auto-renews every 90 days)
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run

# Auto-renewal cron
0 12 * * * /usr/bin/certbot renew --quiet

# Generate self-signed cert for development
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
  -keyout dev.key -out dev.crt \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

# Generate CSR (Certificate Signing Request) for commercial CA
openssl genrsa -out private.key 2048
openssl req -new -key private.key -out request.csr
# Submit request.csr to CA, receive cert.crt back

# Convert formats
openssl pkcs12 -export -out cert.pfx -inkey private.key -in cert.crt  # PEM → PFX
openssl pkcs12 -in cert.pfx -out cert.pem -nodes                      # PFX → PEM

HSTS, Mixed Content & Pinning

# HSTS (HTTP Strict Transport Security)
# Tells browsers: ONLY connect over HTTPS for the next max-age seconds
# Header sent over HTTPS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

# max-age=31536000   = 1 year (recommended minimum)
# includeSubDomains  = applies to all subdomains
# preload            = eligible for browser preload list

# HSTS preload list: browsers ship with a hardcoded list of HSTS domains
# Submit at: https://hstspreload.org
# WARNING: once preloaded, it's very hard to remove - test first!

# Mixed content: page loaded over HTTPS includes HTTP resources
# Active mixed content (scripts, iframes) = BLOCKED by browsers
# Passive mixed content (images) = WARNING, may be blocked
# Fix: ensure all subresources use https:// or protocol-relative //

# Content Security Policy to prevent mixed content:
Content-Security-Policy: upgrade-insecure-requests
# Automatically upgrades HTTP sub-requests to HTTPS

# Certificate Pinning
# HTTP Public Key Pinning (HPKP) - deprecated, caused site outages
# Modern alternative: Expect-CT header + Certificate Transparency logs
Expect-CT: max-age=86400, enforce, report-uri="https://report.example.com/ct"

# Check HSTS and cert with:
curl -I https://example.com | grep -i "strict\|location"
ssl-checker.online   # Free online tool

# nginx HTTPS config
server {
    listen 443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    add_header Strict-Transport-Security "max-age=63072000" always;
}

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free