python 39 lines · 7 steps

Enforcing HTTPS behind a proxy in Flask

A before_request hook redirects insecure traffic to HTTPS and an after_request hook stamps every secure response with HSTS.

Explained by highlit
1from flask import Flask, request, redirect, current_app
2from werkzeug.middleware.proxy_fix import ProxyFix
3 
4app = Flask(__name__)
5app.config.setdefault("FORCE_HTTPS", not app.debug)
6 
7app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)
8 
9 
10@app.before_request
11def enforce_https():
12 if not current_app.config["FORCE_HTTPS"]:
13 return None
14 
15 if request.is_secure:
16 return None
17 
18 if request.headers.get("X-Forwarded-Proto", "http") == "https":
19 return None
20 
21 if request.method not in ("GET", "HEAD"):
22 return (
23 "HTTPS is required for this request.",
24 403,
25 {"Content-Type": "text/plain"},
26 )
27 
28 secure_url = request.url.replace("http://", "https://", 1)
29 return redirect(secure_url, code=301)
30 
31 
32@app.after_request
33def set_hsts(response):
34 if current_app.config["FORCE_HTTPS"] and request.is_secure:
35 response.headers.setdefault(
36 "Strict-Transport-Security",
37 "max-age=31536000; includeSubDomains",
38 )
39 return response
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1When Flask sits behind a proxy, ProxyFix is what lets request.is_secure reflect the real client protocol.
  2. 2Redirect safe methods to HTTPS but reject unsafe ones outright, since a 301 can't preserve a POST body.
  3. 3HSTS should only be sent over already-secure connections, so the browser learns to force HTTPS itself.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Enforcing HTTPS behind a proxy in Flask — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code