Prologue: "Password Visible?!"
As a junior developer, my senior shocked me with this statement:
"Login via HTTP on cafe WiFi? Anyone on the same WiFi network can see your password."
Me: "Really?!"
Senior: "Open Wireshark. Everything's visible. That's why you need HTTPS."
My first reaction was "No way." When I login, the password field shows ***, so how could someone else see it? I couldn't believe it.
Then my senior actually opened Wireshark and showed me logging into our test server. My username and password appeared in plain text on the screen. That night I went home and checked every website in my browser. I changed the password for every site without the 🔒 icon.
Why I Learned This
When I first built a simple internal tool at work, I deployed it with HTTP. It worked fine without issues. Then I asked "Why do we need HTTPS?" and got pressured from three directions:
- CEO: "Google lowers search rankings for HTTP sites. Bad SEO means no traffic."
- Security Team: "It's a privacy law violation. If you have customer data, you'll get fined."
- Senior: "Want to get hacked? Packet sniffing on public WiFi is basic nowadays."
It all came down to money, legal compliance, and security. I immediately got a Let's Encrypt certificate.
What Confused Me Initially
While studying HTTPS, my head spun with questions:
- HTTP vs HTTPS - what's different? Just one "S" makes that much difference?
- SSL? TLS? Which is correct? Certificates are called "SSL certificates," but technical docs say "TLS."
- Why pay for certificates? I heard they used to cost hundreds of dollars per year.
- Let's Encrypt is free - why is it okay? Isn't free more risky?
- Symmetric key? Asymmetric key? Why two keys? Can't we use just one?
Most importantly: "How does encryption actually work?" I couldn't grasp how browsers and servers safely exchange secret keys when they first meet.
The Aha Moment: "Postcard vs Sealed Letter"
My senior's analogy finally made everything click:
HTTP = Postcard: "You sent a postcard from a cafe to your friend. You wrote 'Bank password 1234', The postman, delivery guy, barista - everyone saw it. Your account is now empty."
HTTPS = Sealed Letter + Steel Safe: "Same content in a steel envelope, Locked with 10 padlocks. Only the recipient has the keys. No one can open it mid-delivery."
"Oh, encryption is like an envelope!"
Once I accepted this analogy, everything started making sense. HTTP is a transparent postcard where everyone can see the content. HTTPS is a sealed letter that nobody can open. This concept just clicked in my brain.
HTTP's Fatal Problem
Plain Text Transmission
HTTP transmits all data in plain text. Zero encryption.
Client → Server
POST /login HTTP/1.1
Host: bank.com
Content-Type: application/x-www-form-urlencoded
username=ratia&password=1234
Problem: If someone intercepts this packet? They see everything.
Real Attack: Wireshark
I actually tested this myself:
# 1. Connect to cafe WiFi
# 2. Launch Wireshark
# 3. Filter HTTP packets
http.request.method == "POST"
Result:
POST /login HTTP/1.1
Host: test.local
username=ratia
password=1234
Completely visible! 😱
After this test, I was terrified. I realized that on the public WiFi I use daily, anyone with Wireshark running could see all my passwords.
Man-in-the-Middle Attack
Even scarier is the MITM attack:
Client → [Hacker] → Server
1. Client: "Transfer $100"
2. Hacker: Changes it to "Transfer $1000"
3. Server: "Transfer $1000 complete"
HTTP doesn't guarantee data integrity, so if someone modifies the content mid-transmission, you'd never know.
HTTPS's 3 Guarantees
HTTPS guarantees three things. Let me break them down:
1) Confidentiality
Before encryption:
username=ratia&password=1234
After encryption:
7x9$mK#@pL2qR5vN8cX#Fg2...
Even if a hacker steals the packet, they only see ciphertext. Without decryption, the original data remains hidden.
2) Integrity
Detects if anyone modified the data mid-transmission:
Original: "Transfer $100"
Modified: "Transfer $1000" ← Detected by HMAC!
HTTPS uses a Message Authentication Code (MAC) to verify whether data has been tampered with.
3) Authentication
"Is this really the bank's website?"
Certificates verify the server's identity. Even if a phishing site pretends to be a real bank, without a valid certificate, the browser will show a warning.
SSL vs TLS: Naming Confusion
This confused me the most initially. People call them "SSL certificates," but technical documentation says "TLS."
History
SSL 1.0 (1994) - Scrapped before release (serious security flaws)
SSL 2.0 (1995) - Security vulnerabilities found
SSL 3.0 (1996) - Vulnerable to POODLE attack
───────────────────────────────
TLS 1.0 (1999) - SSL 3.0 upgrade with new name
TLS 1.1 (2006) - Defense against CBC attacks
TLS 1.2 (2008) ← Most widely used currently
TLS 1.3 (2018) ← Latest standard, faster and more secure
Reality:
- Technical name: TLS (Transport Layer Security)
- What people call it: "SSL"
- Certificate name: "SSL certificate" (actually uses TLS)
Why? It stuck! The SSL name became famous first, so people still call it SSL out of habit.
I understood this when I accepted that "SSL is the old name, TLS is current. But people habitually call it SSL."
HTTPS Handshake: 0.1 Second Magic
Understanding how HTTPS starts encrypted communication is the key.
Process
1. Client Hello
Client: "Hi! Want encryption. I support:
- TLS 1.3
- AES-256-GCM
- RSA-2048
- Random Number: a3f82d..."
2. Server Hello
Server: "OK! Let's use TLS 1.3 + AES-256.
Here's my **Certificate**.
Random Number: 8e12c9..."
3. Certificate Verification
Browser: "Is this certificate real? Checking with CA..."
CA: "Yes, it's me, DigiCert. Verify my signature."
Browser: (Verifies signature using DigiCert's public key)
Browser: "Certificate is legit!"
4. Key Exchange
Client: (Generates secret key) → Encrypts with server's public key → Sends
Server: Decrypts with my private key → Got the secret key
Both sides now have the same secret key!
5. Encrypted Communication Starts
From now on, all data encrypted with the shared secret key!
This entire process completes in 0.1 seconds. When we type https:// in the address bar and hit enter, this complex process finishes in the blink of an eye.
Symmetric vs Asymmetric Keys
The core of HTTPS is hybrid encryption - mixing two types of encryption.
Symmetric Key
Same key for encryption/decryption
Encrypt: plaintext + key123 → ciphertext
Decrypt: ciphertext + key123 → plaintext
Pros: Fast ⚡ (AES-256 processes 1GB data in 1 second) Cons: How to safely deliver the key? Sending the key on a postcard defeats the purpose!
Asymmetric Key
Encrypt with public key, decrypt with private key
Encrypt: plaintext + public key → ciphertext
Decrypt: ciphertext + private key → plaintext
Pros: Safe key delivery (public key can be given to anyone) Cons: Slow 🐢 (over 100x slower than symmetric keys)
HTTPS Solution
Hybrid approach!
- Handshake phase: Asymmetric key (safely exchange secret key)
- Data transfer phase: Symmetric key (fast encryption)
Best of both worlds! Security and speed combined.
When I understood this structure, it clicked for me. "Oh, they use both to get only the advantages!"
Certificate
Role
"Proves this site really IS Naver"
Without certificates? Anyone could impersonate naver.com. If a phishing site claims "I'm Naver," should you believe it? Certificates prevent this.
Contents
Subject: naver.com
Issuer: DigiCert (CA)
Valid Period: 2024.01.01 ~ 2025.01.01
Public Key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
Signature: (Signed with DigiCert's private key)
Verification Process
1. Browser: "Is this certificate real?"
2. Browser checks built-in CA list (built into Chrome, Firefox)
3. Verifies signature using DigiCert's public key
4. Signature matches → "It's really Naver!"
5. Signature mismatch → 🚨 "Warning: Untrusted site"
Certificate Chain
Root CA (top-level authority)
└─ Intermediate CA (intermediate authority)
└─ example.com (end certificate)
Browsers only trust Root CAs. Everything else is verified by following the chain upward.
Real Implementation: Let's Encrypt Free Certificate
Here's how I applied HTTPS to our server:
# 1. Install Certbot (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
# 2. Issue certificate (automatic)
sudo certbot --nginx -d example.com -d www.example.com
# Certbot automatically:
# - Verifies domain ownership
# - Issues certificate
# - Modifies Nginx config files
# - Sets up HTTPS redirection
# 3. Set up auto-renewal (certificates expire every 90 days)
sudo certbot renew --dry-run
# 4. Auto-renew with Cron
sudo crontab -e
# Attempt renewal daily at 3 AM
0 3 * * * certbot renew --quiet
Result: Free HTTPS setup in 5 minutes!
We used to pay hundreds of dollars annually for certificates from Comodo or DigiCert. Now it's free thanks to Let's Encrypt. The moment my "certificates = expensive" bias shattered really hit me.
TLS 1.3 Improvements
0-RTT (Zero Round Trip Time)
TLS 1.2 required 2-RTT for handshake:
TLS 1.2:
Client → Server: Client Hello
Client ← Server: Server Hello
Client → Server: Key Exchange
Encrypted communication starts (2 round trips total)
TLS 1.3 reduced it to 1-RTT:
TLS 1.3:
Client → Server: Client Hello + Key Share
Client ← Server: Server Hello + Key Share
Encrypted communication starts (1 round trip total)
0-RTT Resume allows reconnecting to a previously visited server and sending encrypted data immediately without handshake.
TLS 1.3 Resume:
Client → Server: Application Data (encrypted)
Communication starts immediately! (0 round trips)
Speed improvement: First connection 50% faster, reconnection 200% faster
Production Environment Pitfalls
Pitfall 1: Mixed Content
Browsers block HTTP resources on HTTPS pages:
<!-- HTTPS page (https://example.com) -->
<img src="http://cdn.example.com/image.jpg"> ❌ Blocked!
<script src="http://analytics.com/script.js"></script> ❌ Blocked!
Solution:
<!-- Use protocol-relative URLs -->
<img src="//cdn.example.com/image.jpg"> ✅
<script src="//analytics.com/script.js"></script> ✅
<!-- Or change to HTTPS -->
<img src="https://cdn.example.com/image.jpg"> ✅
This actually happened to me. After switching to HTTPS, images didn't load and I panicked. Checking the developer console, I saw "Mixed Content Blocked" errors.
Pitfall 2: Certificate Expiration
Let's Encrypt certificates expire every 90 days. What if you don't set up auto-renewal?
2025-05-14: Certificate issued
2025-08-14: Certificate expires ← Site inaccessible!
Solution: Certbot auto-renewal + monitoring
# Test renewal
sudo certbot renew --dry-run
# Email notification 30 days before expiration
sudo certbot renew --email admin@example.com
Lesson: Our server went down for 3 hours due to certificate expiration. I had to rush to the office at dawn. 😭
Pitfall 3: HSTS (HTTP Strict Transport Security)
HSTS tells browsers "This site must always use HTTPS":
# Nginx configuration
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Benefits:
- Even if you access via HTTP, browser automatically redirects to HTTPS
- Defends against MITM attacks
Warnings:
includeSubDomains: All subdomains must also use HTTPSpreload: Registering on Chrome's HSTS Preload List permanently enforces HTTPS
Pitfall: After setting HSTS, reverting to HTTP is extremely difficult. It's already cached in users' browsers and can't be modified.
Pitfall 4: Self-Signed Certificates
Fine for development environments, but absolutely not for production:
# Generate self-signed certificate for testing
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
Problems:
- Browsers don't trust it
- Users see a 🚨 warning page
- Must click "Advanced → Proceed at your own risk" to access
Solution: Always use Let's Encrypt or commercial CA certificates in production
mTLS: Authentication Between Microservices
Regular HTTPS only authenticates the server. But in microservice environments, you need to authenticate the client too.
mTLS (Mutual TLS)
Regular TLS:
Client → Server: "Show me your certificate to prove you're the real server"
Server → Client: "Here's my certificate"
(Only server authenticated)
mTLS:
Client → Server: "Show me your certificate to prove you're the real server"
Server → Client: "Here's my certificate. Show me yours too"
Client → Server: "Here's my certificate"
(Both sides authenticated)
Use cases:
- Internal communication between microservices
- API Gateway ↔ Backend
- Service Mesh (Istio, Linkerd)
Configuration Example (Nginx)
server {
listen 443 ssl;
# Server certificate
ssl_certificate /etc/ssl/server.crt;
ssl_certificate_key /etc/ssl/server.key;
# Require client certificate
ssl_verify_client on;
ssl_client_certificate /etc/ssl/ca.crt;
}
Certificate Transparency (CT)
Problem: What if a CA issues a fraudulent certificate?
In 2011, DigiNotar CA was hacked and fake google.com certificates were issued. The Iranian government used them to spy on Gmail access.
Solution: Certificate Transparency
1. CA issues certificate
2. Record in CT Log server (public)
3. Anyone can query
4. Suspicious certificate found → Report it
How to check:
# Query certificate history by domain on crt.sh
curl "https://crt.sh/?q=example.com&output=json"
When I queried my own domain, my Let's Encrypt certificate was recorded exactly as issued. That's how transparency is implemented.
Development Environment: localhost HTTPS
Why you need HTTPS testing during development:
- Service Workers require HTTPS
- Geolocation API requires HTTPS
- Payment APIs (Stripe, PayPal) require HTTPS
Generate Local Certificate with mkcert
# 1. Install mkcert
brew install mkcert
# or
curl -JLO "https://dl.filippo.io/mkcert/latest?for=darwin-amd64"
chmod +x mkcert-v*-darwin-amd64
sudo mv mkcert-v*-darwin-amd64 /usr/local/bin/mkcert
# 2. Install local CA
mkcert -install
# 3. Generate localhost certificate
mkcert localhost 127.0.0.1 ::1
# Generated files:
# localhost+2.pem (certificate)
# localhost+2-key.pem (private key)
Using in Node.js
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
const options = {
key: fs.readFileSync('./localhost+2-key.pem'),
cert: fs.readFileSync('./localhost+2.pem')
};
https.createServer(options, app).listen(443, () => {
console.log('HTTPS server running: https://localhost');
});
Now https://localhost works!
Performance: HTTP/2 and HTTPS
HTTPS is a requirement for HTTP/2:
HTTP/1.1 + HTTP: Possible ✅
HTTP/1.1 + HTTPS: Possible ✅
HTTP/2 + HTTP: Impossible ❌
HTTP/2 + HTTPS: Possible ✅
HTTP/2 Benefits:
- Multiplexing: Multiple requests handled simultaneously over one connection
- Server Push: Send resources before client requests
- Header Compression: Eliminate duplicate headers (HPACK)
Speed Comparison:
HTTP/1.1 + HTTPS: Load 100 images → 5 seconds
HTTP/2 + HTTPS: Load 100 images → 2 seconds (60% faster!)
Conclusion: Using HTTPS makes your site faster, not just more secure!
Chrome's "Not Secure" Warning
Accessing HTTP Sites
⚠️ Not Secure
Not HTTPS
Information you enter on this site (passwords, credit cards, etc.) is not secure
Impact:
- User trust declines
- Bounce rate increases
- Google search ranking drops
Accessing HTTPS Sites
🔒 Connection is secure
Certificate is valid (DigiCert)
Effect: User trust ↑
Summary: HTTPS Implementation Checklist
This is the checklist I use when implementing HTTPS in production:
| Item | Description |
|---|---|
| Encryption | Symmetric (fast) + Asymmetric (secure) |
| Certificate | Let's Encrypt (free) or DigiCert (paid) |
| Protocol | TLS 1.2+ (TLS 1.3 recommended) |
| Port | 443 (HTTP is 80) |
| Auto-renewal | Set up Certbot cron (every 90 days) |
| HSTS | Set max-age=31536000 |
| Mixed Content | Change all resources to HTTPS |
| Redirect | HTTP → HTTPS 301 redirect |
| Monitoring | Alert 30 days before certificate expiration |
| SEO | Register HTTPS version in Google Search Console |
| Cost | Let's Encrypt free |
Final Thoughts: "Check the Lock Icon"
Initially, I thought "Why is HTTPS important? HTTP works fine."
Now I habitually check the address bar:
- 🔒 present → Safe to login
- 🔒 absent → Never login
The lessons I learned:
- HTTP is a postcard, HTTPS is a sealed letter: Send passwords in sealed letters.
- Free thanks to Let's Encrypt: Used to be expensive, now setup takes 5 minutes.
- Faster too: HTTP/2 requires HTTPS.
- Auto-renewal essential: Certificate expiration means service downtime means dawn emergency calls.
- Watch Mixed Content: Loading HTTP resources on HTTPS pages gets blocked.
Bottom line: HTTPS isn't optional - it's mandatory. Benefits across security, legal compliance, SEO, and speed.
Send your passwords in sealed letters. 🔒