15.2 HTTPS and TLS
Table of Contents
Why HTTPS Matters for Backend Developers
Most modern websites use HTTPS by default. As a backend developer you must understand what it actually does, why it is required, and how it affects your API design and deployment.
HTTP is plain text. Anyone who can watch the traffic between client and server can read and modify everything. HTTPS is simply HTTP over TLS, which adds encryption and security on top of HTTP.
Backends that handle logins, tokens, payments, or personal data must use HTTPS in production. Browsers and mobile apps also expect HTTPS for modern features like Service Workers and HTTP/2.
Always require HTTPS in production for any application that deals with authentication or user data.
In this chapter you will learn the basics of TLS and certificates, what security guarantees HTTPS provides, and what you must do in your backend code and infrastructure to use HTTPS correctly.
What HTTPS Actually Protects
HTTPS gives three main security properties:
| Property | What it means | Example |
|---|---|---|
| Confidentiality | Attackers cannot read the traffic | Passwords or tokens stay private |
| Integrity | Traffic cannot be silently modified in transit | JSON responses cannot be altered |
| Authentication | Client can verify the server it talks to | api.example.com is really yours |
Confidentiality
With HTTP, a network observer can see:
- Requested URLs
- Headers and cookies
- Request bodies (passwords, tokens, form data)
- Response bodies (HTML, JSON, files)
With HTTPS:
- The URL path and query, headers, and body are encrypted.
- Only a small part of the request is visible, such as the destination IP and the server name (SNI) that is being requested.
Example:
- HTTP login:
- Someone on the same Wi‑Fi can read
POST /login, the username and password. - HTTPS login:
- The attacker can see that you connect to
example.com, but not which endpoint or credentials.
Integrity
Without HTTPS, an attacker can:
- Inject JavaScript into HTML pages.
- Modify JSON responses from your API.
- Strip security headers such as
Strict-Transport-Security.
With HTTPS, if any byte is changed in transit, the TLS layer detects it and the connection is aborted.
Example:
- Your API returns:
{"user_id": 123, "role": "user"}- On HTTP, an attacker could change
"role": "user"to"role": "admin"before it reaches the client. - On HTTPS, this alteration would be detected and rejected.
Authentication (of the server)
HTTPS uses certificates to prove that the client is indeed talking to api.example.com, not to an impostor.
This prevents:
- Man-in-the-middle attacks that pretend to be your server.
- Transparent proxies that terminate your TLS and re-route traffic.
Note that this authenticates the server to the client, not necessarily the client to the server. For client authentication you use sessions, tokens, or mutual TLS, which is out of scope here.
TLS Basics: The Protocol Under HTTPS
TLS (Transport Layer Security) is the protocol that provides the security for HTTPS.
- HTTP + TLS over TCP = HTTPS
- SMTP + TLS over TCP = secure email transfer
- Many application protocols can run "over" TLS
You do not implement TLS in application code yourself. Your web server or reverse proxy (for example Nginx, Caddy, Apache, Traefik, a cloud load balancer) handles TLS.
However, you need to understand the pieces so you can configure it correctly.
TLS Versions
Main versions you will see:
| Version | Status |
|---|---|
| SSL 2/3 | Obsolete and insecure, never use |
| TLS 1.0 | Deprecated |
| TLS 1.1 | Deprecated |
| TLS 1.2 | Widely used, still considered secure |
| TLS 1.3 | Modern, faster, preferred |
Only enable TLS 1.2 and 1.3 for public internet services. Disable SSL and older TLS versions.
In practice, most recommended server configurations today:
- Allow TLS 1.2 and 1.3.
- Prefer TLS 1.3 when possible.
Very High-Level TLS Handshake Overview
A full handshake is complex, but conceptually:
- Client hello
The client says: I want to talk using TLS, here are the cipher suites and TLS versions I support, and the server name (SNI). - Server hello
The server picks the protocol version and cipher suite and sends: - Its certificate (containing its public key and domain).
- Some cryptographic parameters.
- Key exchange
Client and server use asymmetric cryptography to establish a shared secret. With modern TLS, this is usually ephemeral Diffie‑Hellman. - Session keys derived
Both sides derive symmetric keys from the shared secret. - Secure channel established
From then on, all data is encrypted and authenticated with symmetric cryptography.
Mutual authentication (where the client also presents a certificate) is possible but rare for public APIs. Typically only the server is authenticated.
Certificates and Certificate Authorities
TLS uses public key cryptography. Each server has:
- A private key that must be kept secret.
- A public key, embedded in a certificate that can be shared.
What Is a TLS Certificate?
A certificate binds:
- A domain name (for example
api.example.com) - To a public key
- And is signed by a Certificate Authority (CA).
In simplified form, a certificate says:
"The owner of api.example.com controls this public key, and I, the CA, vouch for it."
The browser or HTTP client verifies this statement using the CA's root certificate already built into the operating system or browser.
Fields you will commonly see in a certificate
- Subject: Domain name or organization.
- Subject Alternative Name (SAN): Additional domains or wildcards, for example
*.example.com. - Issuer: The CA that signed the certificate.
- Validity: Not before / not after dates.
- Public key: The server's public key.
- Signature: The CA's cryptographic signature over the certificate data.
Certificate Authorities (CAs)
A CA is a trusted third party that:
- Verifies that you control the domain (for example by DNS record or HTTP challenge).
- Issues a signed certificate.
- The CA's root certificate is trusted by browsers and operating systems.
Popular CAs include:
- Let’s Encrypt (free, automated)
- DigiCert
- GlobalSign
- Sectigo
Do not create self-signed certificates for public production sites. Browsers will warn users, and security is weakened. Use a CA-issued certificate.
Self-signed certificates are fine for internal testing or secure internal systems where you control the trust store.
How the Browser Verifies HTTPS
When a browser connects to https://api.example.com:
- It receives the server's certificate.
- It checks:
- Is the certificate issued by a CA that is in my trusted list?
- Is the certificate currently valid (date range)?
- Does the certificate's domain match the requested domain (
api.example.com)? - Is the certificate signature valid?
- If any of these checks fail, the browser displays a warning such as "Your connection is not private".
As a backend developer, your job is to ensure:
- Your server presents a valid certificate.
- The domain name in the certificate matches your API or site.
- The certificate has not expired.
- Intermediate certificates are configured correctly so clients can build a trust chain from your certificate to a trusted root CA.
How HTTPS Affects Your Backend Code
Most of your HTTPS work happens in server and infrastructure configuration, not inside your Python / application code. However, there are some important points that affect your backend logic.
Absolute vs Relative URLs
When generating URLs in responses or templates, avoid hardcoding http://. Use:
- Relative URLs where possible, for example
/logininstead ofhttp://example.com/login. - Configuration or environment variables for the scheme and host.
If your app runs behind a reverse proxy that terminates TLS, your backend might only see plain HTTP on the internal network. For example:
- Client <HTTPS> Nginx <HTTP> FastAPI
In that case, the backend must rely on headers like X-Forwarded-Proto to know that the original request was HTTPS. Frameworks often have configuration flags to handle this correctly.
Secure Cookies
Cookies that carry authentication or sensitive data must be configured to be used only over HTTPS.
Use these flags:
Secure
Browser sends the cookie only over HTTPS, not over plain HTTP.HttpOnly
JavaScript cannot read the cookie usingdocument.cookie. This helps prevent some XSS attacks from stealing session cookies.SameSite
Controls cross-site cookie sending. For login and CSRF protection you often useSameSite=LaxorSameSite=Strict.
Example of a secure cookie in a response header:
Set-Cookie: session_id=abc123;
Path=/;
HttpOnly;
Secure;
SameSite=Lax
Never send authentication cookies without the Secure and HttpOnly flags in production.
HTTP Strict Transport Security (HSTS)
HSTS tells the browser:
"For this domain, always use HTTPS for the next N seconds, even if the user types http:// or clicks an old http:// link."
You set this with the Strict-Transport-Security header, for example:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadMeaning:
- For 1 year (
31536000seconds): - Only use HTTPS.
- Apply this to all subdomains.
- The domain wants to be included in browser preload lists.
Benefits:
- Prevents downgrade attacks where an attacker tries to redirect users from HTTPS to HTTP.
- Helps ensure that users always use secure connections once they have visited the site once.
Use HSTS only when:
- Your site is fully HTTPS.
- You are confident you will not need HTTP anymore, especially for that domain and subdomains.
Common HTTPS Deployment Patterns
You will often not terminate TLS inside your application server. Instead, you use a reverse proxy or load balancer.
Pattern 1: TLS Termination at Reverse Proxy
Typical stack:
- Internet
- Nginx (handles TLS, HTTPS)
- Uvicorn / Gunicorn (application server, HTTP on localhost)
Flow:
- Client connects to
https://api.example.com. - Nginx handles the TLS handshake and decrypts the traffic.
- Nginx forwards the HTTP request to
http://127.0.0.1:8000. - Application handles the request and sends HTTP response back to Nginx.
- Nginx encrypts it and sends to the client as HTTPS.
Advantages:
- Application code does not deal with TLS directly.
- Easier certificate management and renewal.
- Nginx can handle many connections efficiently.
Pattern 2: TLS Termination at a Cloud Load Balancer
If you use a cloud provider (AWS, GCP, Azure), you might use:
- An HTTP(S) load balancer with a certificate managed by the cloud.
- Containers or VMs behind it that only speak HTTP.
Example on AWS:
- AWS Application Load Balancer terminates TLS with a certificate from AWS Certificate Manager (ACM).
- It forwards HTTP traffic to your ECS / Kubernetes / EC2 services.
From your application's perspective, requests arrive as plain HTTP on an internal network, but externally users only see HTTPS.
Pattern 3: End-to-end TLS
In more secure environments you may:
- Terminate TLS at a load balancer, then
- Use TLS again between the load balancer and backend servers.
This is common in regulated environments where traffic must be encrypted even on internal networks.
Practical HTTPS Guidelines for Backend Developers
When to Use HTTPS
- For all production websites and APIs.
- For any route that:
- Handles login or registration.
- Receives or sends personal or sensitive data.
- Sets or reads authentication cookies.
- Uses tokens like JWTs in headers or bodies.
Redirect HTTP to HTTPS
If clients connect to http://example.com, redirect them to https://example.com.
Example HTTP response:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/At your reverse proxy, you can:
- Listen on port 80 (HTTP).
- Respond with a 301 or 308 redirect to the HTTPS URL.
Do not serve content on HTTP and HTTPS at the same time. That can confuse clients and weaken security.
Check Security After Deployment
After you set up HTTPS:
- Use a browser to check:
- No security warnings.
- The lock icon or security badge.
- Use tools like:
- SSL Labs SSL Server Test (by Qualys).
curl -v https://your-domain.- Confirm:
- Only TLS 1.2 and 1.3 are enabled.
- Strong cipher suites are preferred.
- Certificate chain is complete.
- Certificate is not expired and matches domain.
Example: HTTPS Impact on a Simple FastAPI App
Imagine you have a basic FastAPI app:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/secure-data")
def secure_data():
return JSONResponse({"secret": "only-over-https"})Local development
You often run:
uvicorn main:app --reload --host 0.0.0.0 --port 8000
And access http://localhost:8000/secure-data. This is fine for local development and testing. For real users, you still deploy behind HTTPS.
Production deployment behind Nginx
- Nginx has your certificate.
- Nginx is configured like:
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}- Your app is still just listening on HTTP internally, but clients always use HTTPS.
- In your application, if you need to know whether the request was HTTPS, configure FastAPI / the ASGI server to trust
X-Forwarded-Protofrom Nginx (for example by usinguvicorn --proxy-headersor similar).
Common HTTPS Pitfalls
Mixed Content
If your HTML page is loaded over HTTPS, but it tries to load resources over HTTP, such as:
<script src="http://example.com/script.js"></script>Browsers will block or warn about "mixed content".
Always use:
https://URLs for external resources.- Relative URLs for your own resources.
Using HTTP for API Endpoints in JavaScript
If your frontend is served over HTTPS, calling an HTTP API endpoint from JavaScript is insecure and often blocked.
Example problematic code:
fetch("http://api.example.com/data")Use:
fetch("https://api.example.com/data")or a relative path if you serve frontend and backend from the same origin.
Expired Certificates
Certificates have an expiration date. If you use Let’s Encrypt, certificates are valid for 90 days. You must have an automatic renewal process.
If your certificate expires:
- Browsers will show serious security warnings.
- Many HTTP clients will refuse to connect.
Summary
- HTTPS is HTTP over TLS and provides confidentiality, integrity, and authentication of the server.
- TLS uses certificates issued by trusted CAs to prove that a domain really belongs to the server you are talking to.
- Modern servers should only enable TLS 1.2 and 1.3.
- In most setups, a reverse proxy or load balancer terminates TLS, not your application code.
- As a backend developer, you must:
- Ensure all production traffic uses HTTPS.
- Redirect HTTP to HTTPS.
- Use secure cookies with
SecureandHttpOnly. - Consider HSTS when you are fully on HTTPS.
- Avoid mixed content issues and insecure API calls from HTTPS pages.
- Proper HTTPS and TLS configuration is a central part of backend security and should be treated as a non-negotiable requirement for real-world systems.
Views: 10
KAHIBARO