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.
SSL, TLS, and HTTPS: Securing Web Communication
When you see that padlock icon in your browser, you are seeing TLS (Transport Layer Security) in action. TLS encrypts communication between your browser and the server, preventing eavesdropping and tampering.
The HTTP/HTTPS protocol post covers HTTP at the application layer. This post explains how TLS adds encryption on top, and why it matters.
SSL vs TLS
SSL (Secure Sockets Layer) was invented by Netscape in the mid-1990s. SSL 3.0 was the final version, released in 1996. After SSL 3.0, the protocol was renamed to TLS.
TLS 1.0 came out in 1999, followed by 1.1 (2006), 1.2 (2008), and 1.3 (2018). TLS 1.3 removed obsolete features and significantly simplified the handshake.
Most references to “SSL certificates” today actually refer to TLS certificates. The naming persists because it was already established.
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 the data before transmission.
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
The TLS handshake establishes a secure connection. The exact steps depend on the TLS version and cipher suite, but here is the general idea for TLS 1.2:
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 reduced handshake latency from 2 round trips to 1. It also removed obsolete cipher suites that caused vulnerabilities.
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 specifies which algorithms to use for encryption, authentication, and key exchange. TLS 1.3 simplified cipher suites to five, each supporting different security levels:
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 removed the weak ones.
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 security of the page.
<!-- 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 some mixed content automatically, like scripts. Images and stylesheets may load with warnings.
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.
Let’s Encrypt and Free Certificates
Let’s Encrypt, launched in 2016, revolutionized certificate management. They provide free certificates through an automated process called 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
TLS/HTTPS is essential when:
- You transmit any sensitive data (credentials, personal information, payment data)
- Your application requires user authentication
- You need to protect against man-in-the-middle attacks
- Browser clients access your service (browsers warn on HTTP)
- Your service handles API calls from external clients
- You need to establish trust about server identity
- 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:
- Service-to-service communication in microservices
- API access where you want to verify client identity
- IoT devices where certificates replace passwords
- Zero-trust network architectures
Production Failure Scenarios
| Failure | Impact | Mitigation |
|---|---|---|
| Certificate expired | Browser warnings, service unavailable, revenue loss | Automate renewal with certbot or ACME; alert 30 days before expiration |
| Weak cipher suite enabled | Vulnerable to attacks (POODLE, BEAST, CRIME) | Disable TLS 1.0/1.1; use TLS 1.2+ only; remove 3DES, RC4 |
| Self-signed certificate in production | Browser blocks access; users cannot connect | Use trusted CA certificates (Let’s Encrypt is free) |
| Certificate chain incomplete | Some clients cannot validate; intermittent failures | Include full chain (root, intermediate, server cert) |
| Private key compromised | Attacker can impersonate your server | Rotate certificate immediately; implement key rotation |
| Mixed content on HTTPS page | Unencrypted resources loaded; security warnings | Use HTTPS for all resources; implement CSP |
| OCSP stapling not configured | Additional latency; privacy concerns | Enable OCSP stapling; cache responses |
| TLS 1.3 disabled | Missing performance improvements; weaker security | Enable TLS 1.3; it is faster and more secure |
Observability Checklist
Metrics
- TLS handshake success/failure rate
- Handshake latency (time to complete TLS negotiation)
- Certificate expiration days remaining
- TLS version distribution (TLS 1.2 vs 1.3 ratio)
- Cipher suite usage distribution
- Active TLS connections by version
- mTLS connection rate (if using mutual TLS)
Logs
- TLS handshake failures with reason (certificate expired, wrong host, etc.)
- Certificate validation errors
- OCSP stapling failures
- Weak cipher suite connection attempts
- Client certificate authentication failures
- Unexpected TLS version downgrade requests
Alerts
- Certificate expires within 30 days
- TLS handshake failure rate exceeds 1%
- Weak cipher suite detected in use
- Client certificate authentication failures spike
- Unusual TLS version downgrade attempts
- Certificate chain validation errors increase
Security Checklist
- Use TLS 1.2 minimum (TLS 1.3 preferred)
- Disable TLS 1.0 and TLS 1.1 (deprecated, vulnerable)
- Remove weak cipher suites (3DES, RC4, export ciphers)
- Prefer cipher suites with forward secrecy (ECDHE, DHE)
- Enable HTTP Strict Transport Security (HSTS)
- Include subdomains in HSTS (includeSubDomains)
- Consider HSTS preload for maximum security
- Implement certificate transparency monitoring
- Use CT (Certificate Transparency) logs to detect rogue certs
- Enable OCSP stapling to reduce client latency
- Rotate certificates before expiration
- Use strong private keys (2048-bit RSA minimum, 256-bit ECC preferred)
- Keep certificates separate from application code
- Implement certificate pinning for mobile apps
- Monitor for unauthorized certificates for your domain
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
Quick Recap
Key Bullets
- TLS (Transport Layer Security) encrypts communication between clients and servers
- SSL (Secure Sockets Layer) was the original protocol; TLS is its successor
- TLS uses asymmetric encryption (RSA/ECDSA) to establish a session key, then symmetric encryption (AES) for data transfer
- TLS 1.3 reduced handshake from 2-RTT to 1-RTT with 0-RTT resumption
- Certificates prove server identity through a chain of trust rooted in trusted CAs
- HTTPS is HTTP over TLS, using port 443 by default
- Always use TLS 1.2 or higher; disable older versions
- Forward secrecy ensures past sessions cannot be decrypted if keys are compromised
Copy/Paste Checklist
# Check TLS version and cipher suite of a server
openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep -E "(Protocol|Cipher)"
# Check certificate expiration
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# Check certificate chain
openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep -E "(subject|issuer)"
# Test TLS 1.3 support
openssl s_client -connect example.com:443 -tls1_3 2>&1 | grep "Protocol"
# Check for weak ciphers
nmap --script ssl-enum-ciphers example.com -p 443
# Generate a strong private key and CSR
openssl req -newkey rsa:4096 -keyout key.pem -out request.csr
# Test certificate with specific SNI
openssl s_client -connect example.com:443 -servername example.com
Conclusion
TLS encrypts web traffic, protecting against eavesdropping and tampering. SSL was the original protocol; TLS is its successor. The TLS handshake uses asymmetric encryption to establish a shared key, then symmetric encryption for efficient data transfer.
Certificates prove server identity through a chain of trust rooted in trusted CAs. Modern TLS 1.3 simplified cipher suites and reduced handshake latency. HTTPS combines HTTP with TLS, using port 443 by default.
For the application protocol details, see the HTTP/HTTPS protocol post. For DNS 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.