Skip to content
Home CS Fundamentals HTTP vs HTTPS Explained — How the Web Actually Talks to You

HTTP vs HTTPS Explained — How the Web Actually Talks to You

Where developers are forged. · Structured learning · Free forever.
📍 Part of: Computer Networks → Topic 5 of 22
HTTP and HTTPS explained from first principles.
🧑‍💻 Beginner-friendly — no prior CS Fundamentals experience needed
In this tutorial, you'll learn
HTTP and HTTPS explained from first principles.
  • HTTP is plain text. Every single byte of the conversation can be read by anyone on the network path. Never use it for sensitive data on the public internet in 2026.
  • HTTPS = HTTP + TLS. It simultaneously provides encryption, certificate-based authentication, and integrity. The padlock only proves the first two.
  • The TLS handshake uses asymmetric crypto to safely negotiate a session key, then switches to fast symmetric encryption. This hybrid model is why modern HTTPS has excellent performance, especially with HTTP/3.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
Quick Answer
  • HTTP is plaintext on port 80. Anyone on the path — coffee shop WiFi, ISP, corporate proxy, or nation-state — can read your users' passwords, tokens, and credit cards in cleartext.
  • HTTPS is HTTP inside TLS. It gives you encryption, server authentication, and integrity checks in one package.
  • The TLS handshake uses asymmetric crypto (public/private keys, usually ECDHE) to safely negotiate a session key, then flips to fast symmetric encryption — AES-GCM or ChaCha20 in practice.
  • Port 443 is default for HTTPS. Modern browsers shame HTTP pages with big "Not Secure" warnings, Google continues to downgrade them in search, and features like Service Workers, geolocation, camera access, and Private Access Tokens simply refuse to work on insecure contexts.
  • HTTP/2 and especially HTTP/3 (over QUIC) are HTTPS-only in practice. If you're not on TLS, you're stuck with 20-year-old performance characteristics and head-of-line blocking.
  • The biggest production foot-gun: the padlock only means the pipe is encrypted and the certificate validated for that domain. It says nothing about whether the site is legitimate, the backend is secure, or the code isn't leaking data.
🚨 START HERE
HTTP/HTTPS Quick Debug
Immediate actions when HTTP connections or TLS fail
🟡Certificate expired or expiring soon
Immediate ActionCheck certificate expiry and renew immediately
Commands
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -enddate
certbot renew --force-renewal --dry-run
Fix NowSet cron: 0 3 * * * certbot renew --quiet && systemctl reload nginx || kill -HUP $(pgrep nginx)
🟡HTTP-to-HTTPS redirect not working
Immediate ActionTest both protocols and verify redirect configuration
Commands
curl -sI http://yourdomain.com | head -5
curl -sI http://yourdomain.com | grep -i 'location\|strict-transport'
Fix NowAdd to Nginx: return 301 https://$host$request_uri; (or equivalent at your CDN/load balancer)
🟡Mixed content blocking page elements
Immediate ActionFind all insecure resource references in source and build output
Commands
grep -rn 'http://' . --include='*.html' --include='*.js' --include='*.css' --include='*.json' | grep -v 'https://'
curl -sI https://yourdomain.com | grep -i content-security-policy
Fix NowReplace http:// references with https:// or protocol-relative URLs. Add CSP header with upgrade-insecure-requests while you clean up.
Production IncidentMissing HTTP-to-HTTPS Redirect Exposes Login Credentials on Public Wi-FiAn e-commerce site served both HTTP and HTTPS without a proper redirect. Users who typed the domain or clicked a bookmark without the https:// prefix sent login credentials in plaintext over airport and hotel Wi-Fi.
SymptomSecurity audit found 12% of login requests arriving over HTTP. Session hijacking incidents spiked on public networks. Support tickets showed unauthorized purchases from unfamiliar devices and locations.
AssumptionThe team assumed all traffic was HTTPS because the site displayed a valid certificate and the padlock in testing. They never realized that typing 'example.com' or clicking a plain link defaults to http:// in the browser.
Root causeNo HTTP-to-HTTPS redirect was configured at the edge. The load balancer and web servers listened on port 80 and happily served the full application. No Strict-Transport-Security header was present, so browsers had no memory of preferring HTTPS on future visits. Certificate Transparency logs were being monitored, but that doesn't help if the initial request never uses TLS.
FixImplemented a clean 301 redirect from HTTP to HTTPS on all routes at the load balancer level. Added Strict-Transport-Security header with max-age=31536000; includeSubDomains; preload. Submitted the domain to the HSTS preload list. Added monitoring for any HTTP traffic reaching the application servers.
Key Lesson
Always redirect HTTP to HTTPS at the earliest possible point — never serve real application content on both protocols simultaneously. The redirect itself should be the only thing that ever lives on port 80.HSTS is your memory enforcement layer. Set it with a long max-age on every response (not just the homepage), includeSubDomains, and eventually preload. I've seen teams get burned by setting it only on the root path.Test your setup the way real users and attackers do: curl -I http://yoursite.com should return 301 with a Location header pointing to HTTPS. If you see 200, you're still exposed.HSTS preload protects first-time visitors and removes the initial HTTP window entirely. Submit to the preload list once you're confident in your redirect strategy — it is not easily reversible.
Production Debug GuideSymptom-driven diagnosis for connection and protocol failures
NET::ERR_CERT_DATE_INVALID or similar expiry errors in browserCertificate has expired or is about to. Use openssl s_client or the far more readable ssl-cert-check script to inspect. Renew with certbot renew --force-renewal and reload your services. In 2026 you should have short-lived certs (90 days or less) and automated renewal that alerts at least 7 days early.
Mixed content warnings after HTTPS migrationSome resources (images, scripts, iframes) are still loading via http://. Search your entire codebase and build output. Add Content-Security-Policy: upgrade-insecure-requests as a quick band-aid while you fix the references. Check your CDN configuration too — easy to miss.
CORS errors on API calls between HTTP and HTTPS originsBrowsers treat http://example.com and https://example.com as completely different origins. Standardize on HTTPS everywhere in development and production. The fix is almost always 'use the same protocol as the frontend'.
Secure cookies not sent on local developmentCookies with the Secure flag are ignored over plain HTTP. Stop using plain HTTP for localhost. Use mkcert to generate locally trusted certificates. Your dev environment should match prod behavior as closely as possible.
HTTP/2 or HTTP/3 not working despite server supportBoth require HTTPS in all major browsers. Verify with curl --http2 or --http3. Check ALPN negotiation and make sure you're not accidentally falling back due to old cipher configuration or missing TLS 1.3 support.

Every single time a user opens your site or calls your API, their browser and your server are having a very specific conversation using HTTP or HTTPS. Get this wrong and passwords leak, sessions get hijacked, Google buries you in search, and half your fancy new browser features stop working.

HTTP dates back to 1991. Tim Berners-Lee designed it for simplicity and speed when the web was mostly academic pages. Privacy wasn't even on the radar. Everything travels in plain text. Passwords, session cookies, API keys, credit card details — all completely readable by anyone with a packet sniffer on the same network path.

HTTPS is simply HTTP sent over TLS. The TLS layer adds the three things the original protocol never had: confidentiality through encryption, authentication through certificates, and integrity so tampering is detectable.

By April 2026 this isn't optional theater. Chrome, Firefox, and Safari actively mark HTTP pages as 'Not Secure' with increasingly aggressive UI. Google has been using HTTPS as a ranking signal for years and only gets stricter. Features like geolocation, camera access, service workers, and the newer Private Access Tokens flat-out refuse to work on insecure origins. The real failures I've seen in production aren't usually dramatic MITM attacks — they're the subtle ones: certificates expiring at 3am on a Friday, mixed content quietly breaking payment flows after a frontend change, missing HSTS headers allowing downgrade attacks on public networks, or developers testing exclusively on plain HTTP localhost and getting surprised when prod behaves differently.

Most teams treat HTTPS as a checkbox. The engineers who ship reliably are the ones who understand the handshake, certificate validation chains, Certificate Transparency logs, and the exact guarantees (and limitations) TLS actually provides.

What HTTP Is and How a Browser Actually Fetches a Page

HTTP stands for HyperText Transfer Protocol — the agreed-upon set of rules browsers and web servers follow when talking to each other. When you type a URL and hit Enter, the browser does a DNS lookup, opens a TCP connection on port 80, sends a structured text request, and receives a structured text response containing HTML (and eventually CSS, JS, images, etc.).

A typical modern page still triggers dozens of these request-response cycles. Every asset is its own conversation. The critical reality in 2026 is that all of this is still plain text when using HTTP. Anyone on the network path can read it with trivial tools. This is why HTTP-only sites belong only in controlled internal environments or local development.

io/thecodeforge/network/http_request_demo.py · PYTHON
12345678910111213141516171819202122232425262728293031323334353637
import socket

# io.thecodeforge: Manually craft an HTTP/1.1 request using a raw TCP socket.
# This is exactly what your browser does under the hood (minus all the modern complexity).

HOST = "example.com"
PORT = 80

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

http_request = (
    "GET / HTTP/1.1\r\n"
    "Host: example.com\r\n"
    "Connection: close\r\n"
    "User-Agent: TheCodeForge-Debug/2026\r\n"
    "\r\n"
)

client_socket.sendall(http_request.encode("utf-8"))

response_parts = []
while True:
    chunk = client_socket.recv(4096)
    if not chunk:
        break
    response_parts.append(chunk)

client_socket.close()

full_response = b"".join(response_parts).decode("utf-8", errors="replace")
header_section, _, body_section = full_response.partition("\r\n\r\n")

print("=== HTTP RESPONSE HEADERS ===")
print(header_section)
print("\n=== FIRST 300 CHARS OF BODY ===")
print(body_section[:300])
▶ Output
=== HTTP RESPONSE HEADERS ===
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
Connection: close

=== FIRST 300 CHARS OF BODY ===
<!doctype html>
<html>
<head>
<title>Example Domain</title>
Mental Model
The HTTP Request Lifecycle
Every HTTP request follows the same loop: resolve DNS, open TCP, send request text, receive response text, close connection (or reuse it in newer versions).
  • DNS resolves the domain to an IP address — the phone book of the internet
  • TCP connection on port 80 is the 'phone line' between browser and server
  • The request is structured text: request line, headers, blank line, optional body
  • The response is also structured text: status line, headers, blank line, body (HTML/CSS/JS)
  • Every asset (image, script, CSS, font) triggers its own request-response cycle
📊 Production Insight
HTTP plaintext means any network intermediary can read passwords, tokens, and API keys in transit. I've seen this bite teams on 'internal' tools that suddenly became reachable from coffee shops or via VPN leaks. Rule of thumb I give every team: never send credentials, tokens, or PII over HTTP — even on networks you control. The cost of enabling TLS is negligible compared to the incident you will eventually have.
🎯 Key Takeaway
HTTP is plaintext — every byte is readable by anyone on the network path. Every asset on a page is a separate request-response cycle on port 80. Never send sensitive data over it. The digital equivalent of sending your passwords on a postcard.
HTTP Request Method Selection
IfRetrieving data without side effects
UseUse GET — cacheable, idempotent, no request body
IfCreating a new resource
UseUse POST — not idempotent, request body contains the new data
IfReplacing an entire resource
UseUse PUT — idempotent, request body is the complete replacement
IfUpdating part of a resource
UseUse PATCH — request body contains only the fields to update
IfRemoving a resource
UseUse DELETE — idempotent, no request body typically

Why HTTP Alone Is Dangerous — The Man in the Middle

A Man-in-the-Middle (MITM) attack happens when an attacker inserts themselves between you and the server and can read or modify everything. On plain HTTP this is trivial. Tools like Wireshark, tcpdump, or bettercap make it almost boring. The attacker doesn't need to break any cryptography because there is none.

HTTP has three fatal weaknesses on the public internet: no privacy (everything readable), no integrity (data can be changed silently), and no authentication (you have no proof you're talking to the real server). HTTPS, via TLS, solves all three at once.

io/thecodeforge/network/mitm_illustration.py · PYTHON
12345678910111213141516171819202122232425
# io.thecodeforge: Illustrates what an attacker sees with HTTP vs HTTPS
# This is conceptual — no actual packet sniffing.

import os

# === ATTACKER'S VIEW: Plain HTTP ===
http_login_visible = """
POST /login HTTP/1.1
Host: mybank.com
Content-Type: application/x-www-form-urlencoded

username=alice&password=SuperSecret123&token=abc123
"""

print("=== ATTACKER'S VIEW: Plain HTTP ===")
print("Intercepted request (fully readable):")
print(http_login_visible.strip())

print("\n" + "-" * 60)

# === ATTACKER'S VIEW: HTTPS (TLS encrypted) ===
print("=== ATTACKER'S VIEW: HTTPS (TLS encrypted) ===")
print("Intercepted bytes look like random garbage.")
print("They can see destination IP, port 443, and approximate data size.")
print("They cannot read credentials, tokens, or response bodies.")
▶ Output
=== ATTACKER'S VIEW: Plain HTTP ===
Intercepted request (fully readable):
username=alice&password=SuperSecret123&token=abc123

------------------------------------------------------------
=== ATTACKER'S VIEW: HTTPS (TLS encrypted) ===
Intercepted bytes look like random garbage.
They can see destination IP, port 443, and approximate data size.
They cannot read credentials, tokens, or response bodies.
⚠ Watch Out — HTTPS Is Not a Magic Shield
HTTPS only protects data in transit. Once it reaches your servers, its job is done. If you store passwords in plaintext, have broken access control, or ship vulnerable frontend code, HTTPS won't save you. It secures the tunnel. The endpoints and your application logic are still your responsibility.
📊 Production Insight
MITM attacks on HTTP are trivial on shared networks — airports, hotels, conferences, even some corporate guest WiFi. Session cookies sent over HTTP can be stolen and used to impersonate users without ever knowing their password. The rule I enforce on every project: set the Secure flag on all cookies and use __Host- prefix where possible. I've cleaned up too many incidents where this was missed.
🎯 Key Takeaway
HTTP has no privacy, no integrity, and no authentication — three fatal flaws for anything exposed to the public internet. MITM attacks are not theoretical. HTTPS via TLS solves all three problems with one protocol. Treat plain HTTP as legacy infrastructure in 2026.

How HTTPS Works — TLS, Certificates, and the Handshake Explained

HTTPS is not 'HTTP with encryption bolted on.' It is HTTP transported over TLS (Transport Layer Security). TLS delivers the three properties HTTP lacked: privacy (encryption), authentication (certificates), and integrity (message authentication codes).

The TLS handshake lets the client and server agree on a shared session key using asymmetric cryptography without ever sending the key itself. Once established, they switch to fast symmetric encryption for the actual HTTP traffic. The server proves its identity with a certificate signed by a trusted Certificate Authority. In 2026, that certificate is almost always from Let's Encrypt, and browsers expect TLS 1.3 with modern cipher suites.

io/thecodeforge/network/https_connection_demo.py · PYTHON
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
import ssl
import socket
import json

# io.thecodeforge: Manual HTTPS connection with proper TLS verification
# Demonstrates what browsers do automatically.

HOST = "httpbin.org"
PORT = 443

raw_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

tls_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
tls_context.check_hostname = True
tls_context.verify_mode = ssl.CERT_REQUIRED
# In production you'd also pin or check Certificate Transparency logs

secure_socket = tls_context.wrap_socket(raw_socket, server_hostname=HOST)
secure_socket.connect((HOST, PORT))

print("=== SERVER CERTIFICATE INFO ===")
print(f"Issued to:  {secure_socket.getpeercert().get('subject')}")
print(f"TLS version negotiated: {secure_socket.version()}")

# Send an HTTP request over the now-encrypted channel
http_request = (
    "GET /get HTTP/1.1\r\n"
    f"Host: {HOST}\r\n"
    "Connection: close\r\n"
    "User-Agent: TheCodeForge-Debug/2026\r\n"
    "\r\n"
)
secure_socket.sendall(http_request.encode("utf-8"))

response_chunks = []
while True:
    chunk = secure_socket.recv(4096)
    if not chunk:
        break
    response_chunks.append(chunk)

secure_socket.close()

full_response = b"".join(response_chunks).decode("utf-8", errors="replace")
header_section, _, body_section = full_response.partition("\r\n\r\n")

print("\n=== HTTP RESPONSE STATUS ===")
print(header_section.split("\r\n")[0])
▶ Output
=== SERVER CERTIFICATE INFO ===
Issued to: ((('commonName', 'httpbin.org'),),)
TLS version negotiated: TLSv1.3

=== HTTP RESPONSE STATUS ===
HTTP/1.1 200 OK
Mental Model
The TLS Handshake in 4 Steps
The handshake uses asymmetric crypto to agree on a shared key, then switches to symmetric crypto for speed. TLS 1.3 makes this dramatically faster than the old 1.2 dance.
  • Client sends ClientHello with supported versions, cipher suites, and key share
  • Server replies with ServerHello, its certificate chain, and its own key share
  • Both sides independently compute the same session key (usually via ECDHE)
  • All subsequent data — including the HTTP request — is encrypted with symmetric AES (or ChaCha20) using that key
  • TLS 1.3 does this in 1 round-trip in most cases. 0-RTT is possible but has tradeoffs
📊 Production Insight
TLS 1.2 handshakes with 2 round trips added real latency on high-latency networks. TLS 1.3 is now the default everywhere that matters and cuts that overhead significantly. The gotcha that still bites teams is old load balancers or middleboxes that don't support TLS 1.3 or modern ciphers. Verify with openssl s_client -tls1_3 and monitor your TLS handshake success rate.
🎯 Key Takeaway
TLS gives you encryption, authentication via certificates, and integrity — exactly what plain HTTP lacked. The handshake is asymmetric to safely exchange a key; the actual data transfer is symmetric for performance. In 2026 you should be on TLS 1.3, HTTP/3 where possible, and treating port 443 as the only port that matters for public services.

HTTP Status Codes, Request Methods, and Headers You'll Use Daily

Every HTTP conversation consists of a request and a response, both with strict formatting. Methods describe intent. Status codes tell you what happened. Headers carry metadata that makes the whole system work — caching, authentication, content negotiation, security policies.

GET should be safe and idempotent. POST is the workhorse for mutations. PUT and DELETE are idempotent. PATCH is for partial updates. Knowing the difference isn't academic — it affects caching, retry logic, and whether your API is pleasant to use. Status code families (2xx success, 3xx redirection, 4xx client error, 5xx server error) are the first signal when something breaks.

io/thecodeforge/network/http_methods_demo.py · PYTHON
123456789101112131415161718192021222324252627282930313233343536373839404142
import urllib.request
import urllib.error
import json

# io.thecodeforge: Demonstrating HTTP methods with httpbin.org

BASE_URL = "https://httpbin.org"

def make_request(method: str, path: str, payload: dict = None) -> None:
    url = f"{BASE_URL}{path}"
    body_bytes = json.dumps(payload).encode("utf-8") if payload else None

    request = urllib.request.Request(
        url,
        data=body_bytes,
        method=method,
        headers={
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": "TheCodeForge-Debug/2026"
        }
    )

    try:
        with urllib.request.urlopen(request) as response:
            status_code = response.status
            response_body = json.loads(response.read().decode("utf-8"))
            print(f"[{method}] {url} → {status_code}")
            if "json" in response_body:
                print(f"  Received: {response_body['json']}")
            else:
                ua = response_body.get('headers', {}).get('User-Agent')
                print(f"  User-Agent seen: {ua}")
    except urllib.error.HTTPError as error:
        print(f"[{method}] {url} → {error.code} {error.reason}")
    print()

make_request("GET", "/get")
make_request("POST", "/post", payload={"name": "Alice", "role": "staff-engineer"})
make_request("PUT", "/put", payload={"name": "Alice Chen", "role": "staff-engineer"})
make_request("DELETE", "/delete")
make_request("GET", "/status/404")
▶ Output
[GET] https://httpbin.org/get → 200
User-Agent seen: TheCodeForge-Debug/2026

[POST] https://httpbin.org/post → 200
Received: {'name': 'Alice', 'role': 'staff-engineer'}

[PUT] https://httpbin.org/put → 200
Received: {'name': 'Alice Chen', 'role': 'staff-engineer'}

[DELETE] https://httpbin.org/delete → 200

[GET] https://httpbin.org/status/404 → 404 NOT FOUND
💡401 vs 403 Is a Classic Interview Trap
401 Unauthorized means 'I don't recognize you — please authenticate.' 403 Forbidden means 'I know exactly who you are, and you are not allowed to do this.' Using 401 when you should use 403 leaks whether an account exists. I've seen security auditors flag this exact pattern.
📊 Production Insight
Misusing 401 vs 403 doesn't just confuse developers — it can leak information about valid usernames. Returning 500 for obvious client errors hides real server bugs in monitoring. Map your auth and authorization failures precisely. The status code is the first thing every client, monitoring system, and future developer will see.
🎯 Key Takeaway
Methods define intent. Status codes report outcome. Headers carry the metadata that makes the modern web work. 401 vs 403 is not interchangeable. Status code families are your first debugging signal. Get these right and everything downstream becomes easier.
HTTP Status Code Selection
IfRequest succeeded and returning data
UseUse 200 OK
IfResource created successfully
UseUse 201 Created with Location header
IfClient sent bad data or missing required fields
UseUse 400 Bad Request with error details in body
IfUser not authenticated (no token or invalid token)
UseUse 401 Unauthorized
IfUser authenticated but lacks permission
UseUse 403 Forbidden
IfServer crashed or unhandled exception
UseUse 500 Internal Server Error — log the stack trace, return generic message to client
🗂 HTTP vs HTTPS
The protocol difference that determines whether your users' data is safe
Feature / AspectHTTPHTTPS
Full nameHyperText Transfer ProtocolHTTP Secure (HTTP over TLS)
Default port80443
Data in transitPlain text — readable by anyone on the networkEncrypted — unreadable without the session key
Server authenticationNone — you can't verify who you're talking toYes — via TLS certificate signed by a trusted CA and checked against Certificate Transparency logs
Data integrityNone — data can be modified in transit silentlyGuaranteed — tampering is detected and rejected
Browser indicatorNo padlock; prominent 'Not Secure' warning in 2026 browsersPadlock icon; URL shown as https://
SEO impactGoogle ranks HTTP sites lowerGoogle uses HTTPS as a positive ranking signal
PerformanceSlightly faster with no handshake (but stuck on HTTP/1.1 behavior)TLS 1.3 + HTTP/3 (QUIC) delivers excellent performance; required for modern features
Certificate costN/AFree via Let's Encrypt with automated renewal; paid options for extended validation or specific use cases
Use case todayInternal development, localhost, or air-gapped networks onlyEverything on the public internet — no exceptions in 2026

🎯 Key Takeaways

  • HTTP is plain text. Every single byte of the conversation can be read by anyone on the network path. Never use it for sensitive data on the public internet in 2026.
  • HTTPS = HTTP + TLS. It simultaneously provides encryption, certificate-based authentication, and integrity. The padlock only proves the first two.
  • The TLS handshake uses asymmetric crypto to safely negotiate a session key, then switches to fast symmetric encryption. This hybrid model is why modern HTTPS has excellent performance, especially with HTTP/3.
  • Status codes, request method semantics, 401 vs 403, and proper HSTS configuration are daily tools, not trivia. The teams that get these details right have dramatically fewer production incidents.

⚠ Common Mistakes to Avoid

    Using HTTP for localhost and assuming production HTTPS will behave the same
    Symptom

    Secure cookies don't get sent, mixed-content errors appear in production, CORS and credential behavior differ between dev and prod, leading to late surprises.

    Fix

    Use mkcert (or equivalent) to create locally trusted certificates. Your development environment should mirror production HTTPS behavior as closely as possible. This catches protocol-specific bugs early instead of in production.

    Thinking the padlock means the website is safe or trustworthy
    Symptom

    Users (and sometimes engineers) treat the padlock as a seal of approval. Attackers obtain valid certificates for convincing fake domains with relative ease.

    Fix

    The padlock only means the connection is encrypted and the domain is authenticated. It does not vouch for the business, the code, or the people behind it. Train your users (and your team) to check the actual domain name first.

    Not redirecting HTTP to HTTPS — leaving both protocols active
    Symptom

    Site works on both http:// and https://. Users who omit https:// or follow old links send credentials in plaintext. HSTS is missing so browsers don't remember to upgrade.

    Fix

    Add a 301 redirect from HTTP to HTTPS at the edge. Send Strict-Transport-Security with a long max-age on every response. Test relentlessly with curl. Submit to the HSTS preload list once stable.

    Serving mixed content — loading some resources over HTTP on an HTTPS page
    Symptom

    Padlock disappears or shows warnings. Console flooded with mixed content errors. Active content (scripts, iframes) may be blocked entirely by default in modern browsers.

    Fix

    Hunt down every http:// reference in your codebase, build pipeline, and third-party integrations. Use CSP upgrade-insecure-requests as a safety net while you fix root causes. This mistake still ships surprisingly often.

Interview Questions on This Topic

  • QCan you walk me through exactly what happens when a user types 'https://google.com' in their browser and presses Enter — from DNS lookup through to the page rendering?Mid-levelReveal
    DNS resolution first — the browser asks for the IP of google.com. Then a TCP connection on port 443, followed by the TLS 1.3 handshake: ClientHello, ServerHello + certificate chain, key exchange via ECDHE, derivation of session keys. The certificate is validated against trusted CAs and Certificate Transparency logs. Once the encrypted channel is up, the browser sends an HTTP/3 or HTTP/2 GET request. The server responds with 200 and the HTML. The browser begins parsing, discovers subresources, and repeats the process (often with session resumption for speed). Each step has failure modes I've debugged in production — DNS hijacking, certificate validation failures, handshake timeouts, and mixed content on subresources.
  • QWhat's the difference between symmetric and asymmetric encryption, and which one does TLS use for the actual data transfer — and why?Mid-levelReveal
    Asymmetric encryption uses a public/private key pair. It's secure for key exchange but computationally expensive. Symmetric encryption uses a single shared key and is extremely fast. TLS uses asymmetric cryptography (ECDHE) only during the handshake to securely agree on a session key without transmitting it. After that, all HTTP data is encrypted with fast symmetric algorithms — typically AES-256-GCM or ChaCha20-Poly1305. This hybrid approach is what makes HTTPS both secure and fast enough for the modern web. Understanding this distinction explains why TLS 1.3 is so much quicker than older versions.
  • QIf a site is served over HTTPS, does that mean it's secure? What are the security guarantees HTTPS actually provides, and what are the things it does NOT protect against?JuniorReveal
    HTTPS provides three concrete guarantees: confidentiality (data can't be read in transit), integrity (tampering is detectable), and authentication (you're talking to the real domain, not an impostor). That's it. It does not protect against server-side vulnerabilities (XSS, SQL injection, broken auth), compromised backend systems, phishing sites with valid certificates, malware on the user's device, or social engineering. I've reviewed too many breaches where 'but we had HTTPS' was offered as a defense. HTTPS secures the pipe. Everything else is still your job.
  • QWhat is HSTS (HTTP Strict Transport Security), and why is it critical for preventing SSL-stripping attacks?Mid-levelReveal
    HSTS is a response header that tells the browser 'for the next X seconds, only ever connect to this domain using HTTPS — never attempt plaintext HTTP.' It closes the window where a MITM can strip https:// from links on the first visit. With the preload directive and submission to the browser preload list, even first-time visitors are protected. In practice, I treat HSTS as mandatory for any public site in 2026. The absence of HSTS is one of the first things I look for in a security review.
  • QWhat happens if a browser encounters a certificate where the Common Name doesn't match the URL?JuniorReveal
    The browser aborts the connection and shows a certificate name mismatch error (NET::ERR_CERT_COMMON_NAME_INVALID or equivalent). Modern browsers primarily check the Subject Alternative Name (SAN) extension; the legacy Common Name field is largely ignored if SANs are present. This validation is non-negotiable — it's the main way we prevent an attacker with a valid certificate for evil.com from impersonating bank.com. Wildcard certificates (*.example.com) have limits and don't cover multiple subdomain levels. Get this wrong in production and users see scary errors.

Frequently Asked Questions

Does HTTPS make my website completely secure?

No. HTTPS secures the data while it travels between browser and server. It does not protect against server-side bugs, poor access control, XSS, SQL injection, compromised dependencies, or phishing. Think of it as an armored truck for your data — excellent protection for the journey, but the warehouse at either end can still be robbed.

Is HTTP ever acceptable to use in 2026?

Only for localhost development or completely air-gapped internal networks. Any service reachable from the public internet should be HTTPS-only. Browsers treat plain HTTP as legacy and limit functionality. Use mkcert for local development so your dev environment matches production behavior.

Why does the browser show a padlock — what has it actually verified?

The padlock confirms two things: the connection is encrypted with a strong cipher, and the server presented a valid certificate for exactly that domain, issued by a trusted CA and consistent with Certificate Transparency logs. It does not mean the site is trustworthy, the company is legitimate, or the application is free of vulnerabilities. Valid certificates are easy to obtain for malicious domains.

What is the difference between HTTP/1.1, HTTP/2, and HTTP/3?

HTTP/1.1 is text-based and allows only one request at a time per connection (or uses multiple connections with all the overhead that brings). HTTP/2 is binary, multiplexed, compresses headers, and allows many requests over one connection. HTTP/3 runs over QUIC (UDP-based) instead of TCP, eliminating head-of-line blocking and improving performance on unreliable networks. Both HTTP/2 and HTTP/3 require HTTPS in browsers — another reason TLS is non-negotiable.

🔥
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousTCP vs UDPNext →HTTP/2 and HTTP/3
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged