SSL, TLS, and HTTPS: Securing Web Communication
Understand TLS handshake, certificates, cipher suites, and how HTTPS works. Learn the differences between SSL and TLS and why encryption matters.
Introduction
graph TB
subgraph Application Layer
A[HTTP Data]
end
subgraph TLS Layer
B[TLS 1.3 Record Layer]
C[Handshake Protocol<br/>Key exchange, authentication]
D[Alert Protocol<br/>Error messages]
E[Application Data Protocol<br/>Encrypted payload]
end
subgraph Transport Layer
F[TCP]
end
subgraph Internet Layer
G[IP]
end
A --> B
B --> C
B --> D
B --> E
E --> F
F --> G
Encryption Fundamentals
SSL vs TLS
SSL (Secure Sockets Layer) came from Netscape in the mid-1990s. SSL 3.0 was the last version, released in 1996. After that, the protocol got renamed to TLS.
TLS 1.0 arrived in 1999, then 1.1 (2006), 1.2 (2008), and 1.3 (2018). TLS 1.3 cleaned house — removed obsolete features and streamlined the handshake.
When you see “SSL certificates” referenced today, you’re usually looking at TLS certificates. The old name stuck around.
Why TLS?
Without encryption, anyone on the network path can see what you send and receive. Messages, login credentials, session cookies, everything.
graph LR
A[You] -->|"Sensitive Data"| B[Open WiFi]
B -->|"Anyone can read"| C[Server]
D[Attacker] -->|"Watches traffic"| B
Attackers exploit this in various ways:
- Eavesdropping - Reading data as it travels
- Man-in-the-middle - Intercepting and possibly modifying data
- Session hijacking - Stealing session cookies to impersonate users
- Credential theft - Capturing login forms sent over HTTP
TLS prevents all of these by encrypting everything before it leaves your machine.
Symmetric vs Asymmetric Encryption
TLS uses both types of encryption, for different purposes.
Symmetric Encryption
Symmetric encryption uses the same key to encrypt and decrypt. It is fast and efficient for large data transfers.
Problem: how do both parties get the same secret key without someone else intercepting it?
// Symmetric encryption example
const key = "shared-secret-key-12345";
const encrypted = encrypt(plaintext, key); // One operation
const decrypted = decrypt(encrypted, key); // Same key reverses it
Asymmetric Encryption
Asymmetric encryption uses a key pair: a public key and a private key. What the public key encrypts, only the private key can decrypt, and vice versa.
// Asymmetric encryption example
const { publicKey, privateKey } = generateKeyPair();
const encrypted = encrypt(plaintext, publicKey); // Anyone can encrypt
const decrypted = decrypt(encrypted, privateKey); // Only the private key holder can decrypt
Asymmetric encryption is slower but solves the key exchange problem. You can share the public key openly while keeping the private key secret.
TLS Handshake & Protocol
TLS Handshake
The TLS handshake sets up a secure connection. The exact steps depend on the TLS version and cipher suite, but here is what TLS 1.2 does:
sequenceDiagram
participant Client
participant Server
Client->>Server: ClientHello (supported cipher suites, random number)
Server->>Client: ServerHello (chosen cipher suite, random number)
Server->>Client: Certificate (server's certificate with public key)
Server->>Client: ServerKeyExchange (for some cipher suites)
Server->>Client: CertificateRequest (for client certificates)
Server->>Client: ServerHelloDone
Client->>Server: ClientKeyExchange (premaster secret, encrypted with server's public key)
Client->>Server: ChangeCipherSpec
Client->>Server: Finished (handshake hash)
Server->>Client: ChangeCipherSpec
Server->>Client: Finished
Note over Client,Server: Encrypted tunnel established
The client and server now share a premaster secret, which they combine with the random numbers to derive the session key. All further communication uses this symmetric key.
TLS 1.3 Improvements
TLS 1.3 simplified the handshake:
sequenceDiagram
participant Client
participant Server
Client->>Server: ClientHello (supported cipher suites, key share)
Server->>Client: ServerHello (key share), ChangeCipherSpec, Finished
Client->>Server: ChangeCipherSpec, Finished
Note over Client,Server: 1-RTT handshake (faster)
TLS 1.3 dropped the handshake to 1 round trip. It also removed obsolete cipher suites that caused vulnerabilities.
TLS 0-RTT Resumption
TLS 1.3 introduced 0-RTT (zero round trip) resumption, letting a client send data on the first flight for returning connections.
sequenceDiagram
participant Client
participant Server
Note over Client: Previous session saved
Client->>Server: ClientHello (session ticket, 0-RTT data)
Server->>Client: ServerHello, Finished, 0-RTT data response
Note over Client,Server: 0-RTT - data sent immediately
The client stores a session ticket from the previous handshake. On reconnect, it sends encrypted data alongside the ClientHello, skipping the wait for ServerHello entirely.
How 0-RTT works:
1. First connection: Full handshake, session ticket stored
2. Reconnection: ClientHello + early_data + encrypted ticket
3. Server validates ticket, derives keys, decrypts early_data
4. Response sent immediately - no extra round trip
The replay attack risk: 0-RTT data goes out before the server finishes validating. An attacker can capture and replay those packets. That’s why 0-RTT is unsafe for POST, PUT, DELETE, or anything state-changing. GET requests for static resources are fine.
When to use 0-RTT:
- Repeated API calls to the same endpoint
- Static resource fetching where freshness matters less
- Chat/real-time applications where messages are inherently unique
When to avoid 0-RTT:
- Payment or financial transactions
- Any state-changing operation
- Cases where replay could cause duplicate charges or state corruption
Perfect Forward Secrecy
PFS means compromising one session key cannot reveal past session keys. Without PFS, an attacker with the server’s private key can decrypt all previously captured traffic.
graph LR
A[Session 1 Key<br/>Ephemeral] --> B[Derived from<br/>DH Exchange]
C[Session 2 Key<br/>Ephemeral] --> B
D[Server Private Key<br/>NOT used for sessions] -.->|cannot derive| A
D -.->|cannot derive| C
How ECDHE provides PFS:
// ECDHE key exchange - each session uses fresh ephemeral keys
const crypto = require("crypto");
// Server generates ephemeral key pair for this session only
const serverEphemeral = crypto.generateKeyPairSync("x25519");
// Client generates ephemeral key pair
const clientEphemeral = crypto.generateKeyPairSync("x25519");
// Each side derives shared secret - never transmitted
const sharedSecret = crypto.diffieHellman({
privateKey: serverEphemeral.privateKey,
publicKey: clientEphemeral.publicKey,
});
// Session key derived from shared secret - server private key
// was never used, so compromising it doesn't expose this session
Cipher suites with PFS:
| Key Exchange | Authentication | Provides PFS | TLS 1.3 |
|---|---|---|---|
| ECDHE-RSA | RSA signature | Yes | No (removed) |
| ECDHE-ECDSA | ECDSA sig | Yes | Yes |
| DHE-RSA | RSA signature | Yes | No (removed) |
| RSA | None | No | No (removed) |
TLS 1.3 removed non-PFS cipher suites entirely. All TLS 1.3 connections automatically have PFS through ECDHE.
Without PFS, adversaries who intercepted traffic in the past can decrypt it later if they ever get the private key. The Sony, Yahoo, and Lavabit breaches all showed this was a real threat, not a theoretical one.
Certificates & Cipher Suites
Certificates
TLS certificates prove that a server is who it claims to be. Certificates are issued by Certificate Authorities (CAs).
Certificate Structure
A certificate contains:
- Subject (domain name)
- Issuer (CA name)
- Public key
- Validity period (not before, not after)
- Signature from the CA
# You can view certificate details with openssl
openssl s_client -connect example.com:443 -showcerts
Certificate Chains
Browsers verify certificates through a chain of trust:
graph TD
A[Root CA<br/>Browser trusted] --> B[Intermediate CA<br/>Issued by Root]
B --> C[Your Server Certificate<br/>Issued by Intermediate]
The browser already trusts the Root CA. The Root CA signed the Intermediate CA’s certificate. The Intermediate CA signed your server certificate. This chain of trust verifies your certificate.
Self-Signed Certificates
For testing, you can create self-signed certificates. Browsers do not trust them by default, but they encrypt traffic the same way.
# Generate a self-signed certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Cipher Suites
A cipher suite defines which algorithms to use for encryption, authentication, and key exchange. TLS 1.3 narrowed it down to five options:
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_GCM_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
Each suite specifies:
- Bulk cipher (AES-256-GCM, ChaCha20-Poly1305)
- Authentication algorithm (SHA-384, SHA-256)
- Key exchange method (handled separately in TLS 1.3)
Older TLS versions had dozens of cipher suites, many with known vulnerabilities. TLS 1.3 cut that down to five solid ones.
RSA vs ECDSA Performance Comparison
TLS 1.3 dropped RSA key exchange entirely. RSA certificates still exist for authentication, but if you are getting a new cert today, ECDSA (P-256 or P-384) is the better choice.
// Key generation performance (benchmark comparison)
const { generateKeyPairSync } = require("crypto");
console.time("RSA 2048-bit");
generateKeyPairSync("rsa", { modulusLength: 2048 });
console.timeEnd("RSA 2048-bit");
console.time("ECDSA P-256");
generateKeyPairSync("ec", { namedCurve: "prime256v1" });
console.timeEnd("ECDSA P-256");
// Typical results:
// RSA 2048-bit: ~500ms
// ECDSA P-256: ~5ms (100x faster)
Signature size comparison:
| Algorithm | Key Size | Signature Size | Security Level |
|---|---|---|---|
| RSA 2048 | 2048 bits | 256 bytes | ~112 bits |
| RSA 4096 | 4096 bits | 512 bytes | ~140 bits |
| ECDSA P-256 | 256 bits | 64 bytes | ~128 bits |
| ECDSA P-384 | 384 bits | 96 bytes | ~192 bits |
When to use RSA:
- Compatibility with very old clients (Windows XP SP3, Java 7)
- Hardware tokens that only support RSA
- Environments where ECDSA is not yet supported
When to use ECDSA:
- New certificate deployments
- Performance-critical applications
- Mobile devices (smaller certs = less bandwidth)
- TLS 1.3 deployments (RSA key exchange removed)
Migration path: If you have RSA certificates today, you can gradually transition to ECDSA. Most CAs support both in a chain, and most modern clients prefer ECDSA when available.
HTTPS in Practice
HTTPS in Action
HTTPS is HTTP over TLS. The connection starts as a TCP handshake, then the TLS handshake, then the HTTP request.
sequenceDiagram
participant Browser
participant Server
Browser->>Server: TCP SYN
Server->>Browser: SYN-ACK
Browser->>Server: ACK
Note over Browser,Server: TCP handshake complete
Browser->>Server: TLS ClientHello
Server->>Browser: TLS ServerHello, Certificate
Browser->>Server: TLS ClientKeyExchange, ChangeCipherSpec
Server->>Browser: TLS ChangeCipherSpec, Finished
Note over Browser,Server: TLS handshake complete
Browser->>Server: HTTPS GET /api/data
Server->>Browser: 200 OK (encrypted)
Port 443 is the standard for HTTPS. Port 80 carries HTTP.
Mixed Content
When a page loaded over HTTPS includes resources over HTTP, that is mixed content. The unencrypted resources can be intercepted or modified, undermining the page’s security.
<!-- Bad: HTTP resource on HTTPS page -->
<img src="http://example.com/image.png" />
<!-- Good: HTTPS resource -->
<img src="https://example.com/image.png" />
Modern browsers block active mixed content (scripts, iframes) automatically. Passive content like images may still load, just with warnings in the console.
Certificate Validation
When your browser connects to a server, it validates the certificate:
- Check the certificate is not expired
- Verify the signature chain leads to a trusted CA
- Check the domain name matches the certificate
- Check for revoked certificates (via CRL or OCSP)
// Node.js validates certificates by default
const https = require("https");
https.get("https://example.com", (res) => {
// Certificate is automatically validated
});
For production systems, proper certificate validation is critical. Never disable validation in production code.
Certificate Transparency
CT is an open framework for monitoring and auditing TLS certificates. It prevents Certificate Authorities from issuing certs without public knowledge.
graph TD
A[CA Issues Certificate] --> B[CT Log Server<br/>append-only database]
B --> C[Monitors scan logs<br/>for your domain]
C --> D[Alert if unexpected<br/>certificate appears]
E[Attacker tries to<br/>issue rogue cert] --> F[CT log captures it]
F --> G[Alert fires before<br/>attack succeeds]
How CT works:
# View CT PreCertificate log entries for a domain
# Certificates are submitted to multiple independent logs
certspotter -d example.com
# Or use crt.sh to search for all issued certificates
curl -s "https://crt.sh/?q=example.com&output=json" | jq .
# Check SCT (Signed Certificate Timestamp) presence
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -text | grep -A 1 "Signed Certificate Timestamp"
The DigiNotar breach in 2011 showed what happens without CT: a Dutch CA issued fraudulent certificates for Google, and Iranian attackers used them to spy on Gmail users in Iran. CT makes this much harder by requiring all certificates to be publicly logged. Rogue certs get spotted by monitors before they can do damage.
SCT delivery methods:
| Method | How client gets SCT | Pros | Cons |
|---|---|---|---|
| X.509 extension | SCT embedded in certificate | Self-contained | Certificate must be reissued |
| TLS extension | SCT sent during TLS handshake | No cert changes | Extra round trip |
| OCSP stapling | SCT stapled with OCSP response | Combined validation | Complex implementation |
HSTS Preload Deep Dive
HSTS (HTTP Strict Transport Security) tells browsers to only connect via HTTPS. The preload list goes further—browsers ship your domain as HTTPS-only by default, before any visit.
# Standard HSTS - requires first visit to learn
Strict-Transport-Security: max-age=31536000; includeSubDomains
# HSTS Preload - baked into browsers
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Requirements for preload submission:
1. max-age must be at least 63072000 (2 years)
2. includeSubDomains must be present
3. preload flag must be set
4. Redirect all HTTP to HTTPS on the same host
5. Serve valid certificates on all subdomains
6. Serve a valid certificate chain (not self-signed)
Submit at hstspreload.org. Once you’re in, getting out takes months—browsers cache the preload list aggressively.
Check preload status:
# Check if a domain is preloaded
curl -s "https://hstspreload.org/api/v2/entries" | \
jq '.[] | select(.name == "example.com")'
Trade-off analysis for preload:
| Factor | Without Preload | With Preload |
|---|---|---|
| First visit protection | No | Yes |
| Removal speed | Fast (update DNS) | Slow (6-12 months) |
| Subdomain requirements | Flexible | All must support HTTPS |
| Risk of lockout | Low | High if misconfigured |
Certificate Providers & mTLS
Let’s Encrypt and Free Certificates
Let’s Encrypt, launched in 2016, made certificates free and automated through ACME (Automated Certificate Management Environment).
# Certbot automates certificate issuance and renewal
certbot --webroot -w /var/www/html -d example.com -d www.example.com
Certificates from Let’s Encrypt are just as valid as paid certificates. They expire every 90 days, but automated renewal handles this seamlessly.
When to Use TLS/HTTPS
Reach for TLS/HTTPS when you transmit any sensitive data, your application requires user authentication, or browsers access your service. Also when you need to protect against man-in-the-middle attacks, your service handles API calls from external clients, or compliance requires encryption (PCI-DSS, HIPAA, GDPR).
When Not to Use TLS
TLS may add unnecessary overhead when:
- You are on a completely trusted network (isolated internal services)
- Performance is critical and encryption overhead matters (high-frequency trading)
- You need to debug traffic in development (but use self-signed certs)
- Legacy systems cannot support TLS (gradually migrate)
When to Use Mutual TLS (mTLS)
mTLS requires both client and server to present certificates. Use it for service-to-service communication in microservices, API access where you want to verify client identity, IoT devices where certificates replace passwords, and zero-trust network architectures.
Trade-off Analysis
TLS Version Comparison
| Factor | TLS 1.0/1.1 | TLS 1.2 | TLS 1.3 |
|---|---|---|---|
| Handshake round trips | 2-RTT | 2-RTT | 1-RTT (0-RTT resumption) |
| Forward secrecy | Optional | Optional | Mandatory |
| Cipher suites | Many vulnerable | Many options | 5 suites only |
| 0-RTT data | Not supported | Not supported | Supported |
| RSA key exchange | Supported | Supported | Removed |
| Security risk | High (deprecated) | Medium | Low |
| Client compatibility | Legacy systems | Most systems | Modern systems |
Certificate Type Comparison
| Factor | Self-Signed | Let’s Encrypt | Commercial CA |
|---|---|---|---|
| Cost | Free | Free | $10-500/year |
| Trust level | None (browsers block) | Full (trusted) | Full (trusted) |
| Validity period | Any | 90 days | 1-2 years |
| Renewal automation | Manual | ACME (automated) | Varies |
| Support | None | Community | Vendor support |
| Use case | Testing only | Most websites | Enterprise/EV certs |
Encryption Algorithm Comparison
| Algorithm | Key Size | Speed | Signature Size | Recommended Use |
|---|---|---|---|---|
| AES-128-GCM | 128 bit | Fast | N/A | Performance-critical TLS |
| AES-256-GCM | 256 bit | Fast | N/A | High-security TLS |
| ChaCha20-Poly1305 | 256 bit | Fast on mobile | N/A | Mobile/ARM devices |
| RSA 2048 | 2048 bit | Slow | 256 bytes | Legacy compatibility |
| RSA 4096 | 4096 bit | Very slow | 512 bytes | High-security legacy |
| ECDSA P-256 | 256 bit | Very fast | 64 bytes | Modern deployments |
| ECDSA P-384 | 384 bit | Fast | 96 bytes | High-security modern |
Production Failure Scenarios
| Failure | Impact | Mitigation |
|---|---|---|
| Certificate expired | Browser warnings, users cannot connect, revenue loss | Set up automated renewal (certbot/ACME); alert 30 days before expiry |
| Weak cipher suite enabled | Vulnerable to POODLE, BEAST, CRIME attacks | Disable TLS 1.0/1.1; only allow TLS 1.2+; remove 3DES, RC4 |
| Self-signed certificate in production | Browser blocks access entirely | Use a trusted CA (Let’s Encrypt is free) |
| Certificate chain incomplete | Some clients fail to validate; intermittent outages | Include full chain: root + intermediate + server cert |
| Private key compromised | Attacker can impersonate your server | Rotate immediately; have a key rotation plan ready |
| Mixed content on HTTPS page | Unencrypted resources load; security warnings | Serve all resources over HTTPS; set up CSP |
| OCSP stapling not configured | Extra latency per connection; privacy leak | Enable stapling; cache OCSP responses |
| TLS 1.3 disabled | Slower handshakes; weaker security by default | Turn on TLS 1.3—it’s faster and more secure |
Common Pitfalls / Anti-Patterns
Disabling Certificate Validation
Never disable certificate validation in production code, not even for simplicity.
// DANGEROUS - Never do this
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
// Instead, use proper certificates
const https = require("https");
const options = {
cert: fs.readFileSync("/path/to/cert.pem"),
key: fs.readFileSync("/path/to/key.pem"),
ca: fs.readFileSync("/path/to/ca.pem"), // Certificate authority chain
};
Using Self-Signed Certificates in Production
Self-signed certificates work for testing but break trust in browsers.
# Self-signed is OK for development
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
# For production, use Let's Encrypt (free)
certbot --webroot -w /var/www/html -d example.com
Not Including Full Certificate Chain
Missing intermediate certificates cause validation failures.
# Check certificate chain
openssl s_client -connect example.com:443 -showcerts
# Should show: Server cert -> Intermediate CA -> Root CA
# If chain is incomplete, some clients will fail
Ignoring Mixed Content Warnings
HTTPS pages loading HTTP resources are vulnerable.
<!-- BAD - HTTP resource on HTTPS page -->
<script src="http://example.com/app.js"></script>
<!-- GOOD - All resources use HTTPS -->
<script src="https://example.com/app.js"></script>
Not Implementing HSTS
Without HSTS, attackers can strip HTTPS and intercept traffic.
# Good HSTS header
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Even better - preload HSTS
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Best Practices Summary
Server Configuration
Turn on TLS 1.3 and disable 1.0/1.1 entirely. Those older versions have well-documented flaws (BEAST, POODLE, ROHCH) and no legitimate reason to still be enabled. Use AES-256-GCM or ChaCha20-Poly1305 with ECDHE key exchange—nothing else.
Enable HSTS and submit to the preload list. Without it, the first request to your site is still vulnerable to downgrade attacks. Once you’re on the preload list, that protection starts from the first byte transferred.
Configure OCSP stapling so clients do not have to call your CA to check certificate validity. It reduces latency and means the CA does not see every domain your users visit.
Set up certificate transparency monitoring. You can use crt.sh or a paid monitor to alert you whenever a certificate is issued for your domain.
Managing Certificates
Automate renewal. Certbot + Let’s Encrypt is free and handles 90-day renewals. Set your alert threshold at 30 days, not 7—when expiration hits, it is already too late.
Always include the full certificate chain. Root + intermediate + server cert. Missing intermediates cause cryptic failures that are hard to debug.
Rotate keys regularly and store them separately from application code. Use a secrets manager. Never commit a private key to a repository.
For new certificates, prefer ECDSA over RSA. Smaller keys, faster operations, strong security.
Application Security
Redirect all HTTP to HTTPS. No exceptions. Mixed content undermines your HTTPS setup—serve everything over TLS.
Set the Secure and HttpOnly flags on session cookies. Without them, cookies leak through non-HTTPS connections.
For mobile apps and high-security applications, implement certificate pinning. It prevents MITM attacks even if a CA is compromised.
Monitoring
Watch your TLS version distribution. If TLS 1.2 is still above 30% of connections after two years of TLS 1.3 being mainstream, something is wrong.
Alert on certificate expiration (30 days), handshake failure spikes, and unusual downgrade attempts. Log handshake failures with cipher suite, TLS version, and client IP for forensics.
Development Practices
Never disable TLS validation in code—not for “internal” services, not for localhost, not for anything. If you think you need to, you are wrong.
Test your TLS configuration with Qualys SSL Labs and testssl.sh. Design your systems to rotate certificates without downtime.
Interview Questions
SSL (Secure Sockets Layer) was invented by Netscape in the 1990s, with SSL 3.0 being the final version in 1996. TLS (Transport Layer Security) is the successor protocol, starting with TLS 1.0 in 1999. The main differences are that TLS has stronger cipher suites, improved security mechanisms, and TLS 1.3 specifically reduced handshake latency and removed vulnerable features. Most "SSL certificates" today actually use TLS protocol.
The TLS 1.2 handshake involves: (1) Client sends ClientHello with supported cipher suites and a random number, (2) Server responds with ServerHello, chosen cipher suite, and its random number, (3) Server sends its certificate containing the public key, (4) Server may send ServerKeyExchange for certain cipher suites, (5) Server sends ServerHelloDone, (6) Client sends ClientKeyExchange containing a premaster secret encrypted with the server's public key, (7) Both parties derive session keys from premaster secret and random numbers, (8) ChangeCipherSpec messages are exchanged, (9) Finished messages verify the handshake. This takes 2 round trips before encrypted data can be sent.
TLS 1.3 improvements include: (1) Reduced handshake to 1-RTT (or 0-RTT for resumption), down from 2-RTT, (2) Removed RSA key exchange and other non-PFS cipher suites, (3) Simplified to only five cipher suites, all providing forward secrecy, (4) 0-RTT resumption allows sending data on the first flight for returning clients, (5) Removed obsolete features like renegotiation, (6) Better resistance to downgrade attacks. The result is faster connections with stronger security by default.
Perfect Forward Secrecy (PFS) ensures that compromising one session key cannot reveal past session keys. Without PFS, if an attacker obtains the server's private key, they can decrypt all previously captured traffic. With PFS, each session uses ephemeral keys derived from Diffie-Hellman key exchange—compromising the server's long-term private key does not expose past sessions. TLS 1.3 mandates PFS for all connections. Major breaches have demonstrated why PFS matters: stored encrypted traffic becomes readable if the private key is later compromised.
A Certificate Authority (CA) is a trusted entity that issues digital certificates. The chain of trust works hierarchically: browsers ship with a list of trusted Root CAs. Root CAs issue certificates to Intermediate CAs, which in turn issue server certificates. When connecting to a server, the browser receives the server certificate, verifies it was signed by its Intermediate CA, verifies that Intermediate was signed by a Root CA, and checks that the Root is in the browser's trusted store. If any link in the chain is broken or the certificate is expired, validation fails.
Mixed content occurs when an HTTPS page loads resources (images, scripts, stylesheets) over HTTP. The problem is that while the main page is encrypted, the HTTP resources are transmitted in cleartext. An attacker performing a man-in-the-middle can intercept and modify these unencrypted resources. For scripts, this allows complete page compromise. Modern browsers block some mixed content (especially active content like scripts), while passive content (images) may load with warnings. The fix is to ensure all resources use HTTPS URLs.
OCSP (Online Certificate Status Protocol) stapling allows the server to cache the CA's OCSP response and send it to clients during the TLS handshake. Normally, clients must contact the CA's OCSP server to check if a certificate is revoked, adding latency and privacy concerns (the CA knows which site you're visiting). With OCSP stapling, the server includes the cached OCSP response, proving the certificate is still valid without the client making an extra network request. This reduces latency, improves privacy, and provides a better user experience.
TLS uses both types for different purposes. Asymmetric encryption (RSA, ECDSA) uses a key pair—data encrypted with the public key can only be decrypted with the private key. It's used during the handshake to securely exchange a premaster secret and for authentication. Symmetric encryption (AES, ChaCha20) uses the same key for encryption and decryption. It's much faster and used for the actual data transfer after the handshake. The workflow is: asymmetric encryption establishes a shared secret during handshake, then symmetric encryption uses that shared secret for efficient bulk data transfer.
Certificate Transparency is an open framework for monitoring and auditing TLS certificates. It was created after incidents like the DigiNotar breach, where a CA issued fraudulent certificates for Google without detection. CT requires CAs to submit all certificates to append-only log servers. Monitors watch these logs for certificates issued for domains they control. If a rogue certificate appears, it's detected immediately. Browsers require Signed Certificate Timestamps (SCTs) from CT logs as proof of logging. This means unauthorized certificates for your domain can be detected before they're used for attacks.
Mutual TLS (mTLS) requires both the client and server to present certificates and authenticate each other. In standard TLS, only the server presents a certificate (server authentication), but with mTLS, the client must also have a valid certificate issued by a trusted CA. mTLS is used for: (1) service-to-service communication in microservices where you want to verify each service's identity, (2) API access control beyond API keys, (3) zero-trust architectures where every request must be authenticated, (4) IoT deployments where certificates replace passwords. It provides stronger authentication than single-sided TLS but requires more complex certificate management.
HTTP Strict Transport Security (HSTS) is a header that tells browsers to only connect via HTTPS for a specified duration. Standard HSTS requires the browser to first visit the site over HTTPS to learn the HSTS policy. HSTS preload goes further—domains are submitted to a list compiled into browsers, so new visitors automatically use HTTPS even on first visit. Preload requirements are stricter: max-age of at least 2 years, includeSubDomains flag, and all subdomains must support HTTPS. The tradeoff is that removal from preload takes months due to aggressive caching.
TLS 0-RTT resumption allows clients to send encrypted data on the first flight during reconnection, skipping the round trip for the ServerHello. The security risk is replay attacks: because the 0-RTT data is sent before the server fully validates the connection, an attacker can capture and replay those packets. This makes 0-RTT unsafe for non-idempotent requests like POST, PUT, DELETE, or any state-changing operation. It's safe for repeated GET requests for static resources. Applications using 0-RTT must carefully design their protocols to only send idempotent data in the early_data field.
RSA and ECDSA differ in key size, performance, and compatibility. RSA 2048-bit provides ~112 bits of security with 256-byte signatures, while ECDSA P-256 provides ~128 bits with only 64-byte signatures. ECDSA is roughly 100x faster at key generation and produces smaller certificates. RSA has better compatibility with very old clients (Windows XP, Java 7). For new deployments, ECDSA is preferred due to better performance and smaller certificates. TLS 1.3 removed RSA key exchange entirely but still supports RSA certificates for authentication. Many organizations use ECDSA certificates while maintaining RSA fallback for legacy compatibility.
For TLS 1.3, only five cipher suites exist, all providing forward secrecy: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256, TLS_AES_128_CCM_SHA256, and TLS_AES_128_CCM_8_SHA256. For TLS 1.2, enable only ECDHE or DHE cipher suites with AES-GCM or ChaCha20-Poly1305. Disable TLS 1.0 and 1.1 entirely. Remove 3DES, RC4, export ciphers, and any cipher not providing forward secrecy. Use Mozilla SSL Configuration Generator for specific server configurations. The principle is: fewer cipher suites with strong algorithms is better than many options.
To troubleshoot certificate validation: (1) Check certificate expiration with `openssl s_client` or SSL Labs, (2) Verify the full certificate chain is present using `openssl s_client -showcerts`, (3) Confirm the domain name matches the certificate SAN, (4) Check for revocation using OCSP or CRL, (5) Ensure intermediate certificates are properly installed on the server, (6) For self-signed certs, verify the CA is in the trust store, (7) Check for certificate chain ordering issues, (8) Ensure Server Hello doesn't truncate the chain for older clients. Tools like `testssl.sh` and Qualys SSL Labs provide comprehensive analysis. Certificate chain issues often cause intermittent failures depending on the client's trusted CA store.
A TLS downgrade attack forces a connection to use an older, weaker TLS version. Attackers intercept the ClientHello and strip out modern cipher suites, making the client believe the server only supports older versions. TLS 1.3 prevents downgrade attacks through: (1) A special downgrade sentinel mechanism in the ServerHello—when a server supporting TLS 1.3 receives a ClientHello without TLS 1.3 cipher suites, it signals this via a special flag, (2) Mandatory forward secrecy—all TLS 1.3 connections use ephemeral keys, (3) Removing obsolete features like renegotiation that could be exploited. The BEAST, POODLE, and FREAK attacks all exploited downgrade vulnerabilities in older TLS versions.
In an HTTP MITM attack, the attacker positions themselves on the network path between client and server. They can: (1) Eavesdrop on all unencrypted traffic, capturing credentials, session cookies, and sensitive data, (2) Modify requests and responses, injecting malicious content or altering data, (3) Terminate the connection and impersonate the server to the client, and vice versa. HTTPS prevents MITM through: (1) Server authentication via certificates—the server proves its identity through a CA-signed certificate, (2) Encryption—Even if intercepted, traffic is unreadable without the session key, (3) Integrity checking—TLS adds MAC to prevent tampering. The padlock icon confirms the server is authenticated and the connection is encrypted.
Certificate pinning restricts which certificates are trusted for a given domain beyond the normal CA chain. The server explicitly tells clients which certificate or public key to expect, preventing attacks even if a CA issues a fraudulent certificate. Implementation methods: (1) Pin the leaf certificate directly, (2) Pin the SubjectPublicKeyInfo (SPKI) which survives key rotation, (3) Use a backup pin for redundancy. Trade-offs: Pinned certificates break during key rotation unless properly planned—mobile apps frequently fail after server key updates. The standard CA model is more flexible: CAs handle revocation and expiration automatically. Pinning is high-maintenance but provides defense-in-depth against CA compromise, which is why it's used by major browsers and mobile banking apps despite the operational overhead.
Session ID resumption (TLS 1.2): Server stores session state indexed by a session ID. Client includes the session ID in ClientHello, server looks up state and resumes. Limitation: requires server-side state and doesn't work across load-balanced servers. Session ticket resumption (TLS 1.2/1.3): Server encrypts session state into a ticket and sends it to the client. Client presents the ticket on resumption. Works across servers since only the server can decrypt the ticket. PSK (TLS 1.3): Pre-shared key combines ticket and early data. Client and server share a secret established in a previous handshake. Use session tickets for stateless load-balanced environments. Use PSKs for 0-RTT data and latency-critical connections. Avoid session IDs in modern deployments due to their stateful nature.
Running HTTPS-only provides the strongest security posture: all traffic is encrypted, no downgrade attacks are possible, HSTS headers are effective, and there's no risk of mixed content. Allowing both HTTP and HTTPS creates vulnerabilities: (1) HTTP endpoints can be intercepted before redirect, allowing MITM attacks to steal credentials or inject code, (2) Attackers can prevent the redirect and keep users on HTTP, (3) Session cookies without the Secure flag can be transmitted over HTTP, leaking sessions. Mixed content on HTTPS pages also creates vulnerabilities when HTTP resources are loaded. Best practice is HTTPS-only with HTTP-to-HTTPS redirects at the server level (before application code runs), HSTS headers, and the Secure flag on all cookies. For static sites, serve exclusively on port 443.
Further Reading
Official Specifications
- RFC 8446 - TLS 1.3 - The definitive TLS 1.3 specification
- RFC 5246 - TLS 1.2 - TLS 1.2 specification
- RFC 7525 - Recommendations for TLS - BCP 195 security recommendations
Certificate Management
- Let’s Encrypt Documentation - Free certificate issuance and automation
- Certbot Documentation - ACME client setup guides
- Certificate Transparency - Official CT project site
- crt.sh - Certificate search and monitoring tool
Security Best Practices
- Mozilla SSL Configuration Generator - Hardened server configurations
- Qualys SSL Labs - TLS configuration analyzer
- HSTS Preload List - Submit and check preload status
Tools and Testing
- OWASP TLS Cipher String Knowledge - Security cheat sheet
- testssl.sh - Command-line TLS testing tool
- SSLyze - Python TLS analysis library
Conclusion
TLS protects web traffic from eavesdropping and tampering. SSL came first; TLS is its modern replacement. The handshake uses asymmetric encryption to set up a shared key, then symmetric encryption takes over for the actual data transfer.
Certificates prove the server is who it claims to be, verified through a chain rooted in trusted CAs. TLS 1.3 brought fewer cipher suites, a faster handshake, and mandatory forward secrecy.
HTTPS is just HTTP over TLS on port 443.
For how HTTP works at the application layer, see the HTTP/HTTPS protocol post. For DNS and domain security, see the DNS & Domain Management post.
Category
Related Posts
Cloud Security: IAM, Network Isolation, and Encryption
Implement defense-in-depth security for cloud infrastructure—identity and access management, network isolation, encryption, and security monitoring.
Kubernetes Network Policies: Securing Pod-to-Pod Communication
Implement microsegmentation in Kubernetes using Network Policies to control traffic flow between pods and enforce zero-trust networking.
mTLS: Mutual TLS for Service-to-Service Authentication
Learn how mutual TLS secures communication between microservices, how to implement it, and how service meshes simplify mTLS management.