from flask import Flask, redirect, request
app = Flask(__name__)
@app.before_requestdefredirect_to_https():
"""Enforce HTTPS for all requests"""ifnot request.is_secure and app.config.get('FORCE_HTTPS'):
url = request.url.replace('http://', 'https://', 1)
return redirect(url, code=301)
X-Frame-Options
Clickjacking Prevention
# Deny all framing (most secure)
response.headers['X-Frame-Options'] = 'DENY'# Allow framing from same origin
response.headers['X-Frame-Options'] = 'SAMEORIGIN'# Allow framing from specific domain (deprecated, use CSP)
response.headers['X-Frame-Options'] = 'ALLOW-FROM https://trusted.com'# Modern alternative: CSP frame-ancestors
response.headers['Content-Security-Policy'] = "frame-ancestors 'none'"# Deny
response.headers['Content-Security-Policy'] = "frame-ancestors 'self'"# Same origin
response.headers['Content-Security-Policy'] = "frame-ancestors https://trusted.com"# Specific domain
Cross-Origin Resource Sharing (CORS)
CORS Configuration
from flask_cors import CORS
# Allow all origins (development only)
app = Flask(__name__)
CORS(app) # ⚠️ Not for production# Specific origin
CORS(app, origins=['https://example.com'])
# Multiple origins with credentials
CORS(app,
origins=['https://app1.example.com', 'https://app2.example.com'],
supports_credentials=True,
allow_headers=['Content-Type', 'Authorization'],
expose_headers=['X-Total-Count'],
max_age=3600)
# Manual CORS handling@app.after_requestdefadd_cors_headers(response):
origin = request.headers.get('Origin')
# Whitelist allowed origins
allowed_origins = [
'https://app.example.com',
'https://admin.example.com'
]
if origin in allowed_origins:
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
response.headers['Access-Control-Max-Age'] = '3600'return response
# Preflight request handler@app.route('/<path:path>', methods=['OPTIONS'])defhandle_preflight(path):
"""Handle CORS preflight requests"""return'', 204
CORS Security Considerations
# ❌ VULNERABLE - Reflecting Origin header@app.after_requestdefvulnerable_cors(response):
# Never do this - allows any origin
origin = request.headers.get('Origin')
response.headers['Access-Control-Allow-Origin'] = origin # VULNERABLEreturn response
# ✅ SECURE - Whitelist validation@app.after_requestdefsecure_cors(response):
origin = request.headers.get('Origin')
# Validate against whitelistif origin in ALLOWED_ORIGINS:
response.headers['Access-Control-Allow-Origin'] = origin
elif'*'in ALLOWED_ORIGINS andnot CREDENTIALS_REQUIRED:
# Only allow wildcard without credentials
response.headers['Access-Control-Allow-Origin'] = '*'return response
Other Security Headers
X-Content-Type-Options
# Prevent MIME type sniffing
response.headers['X-Content-Type-Options'] = 'nosniff'# Ensures browsers respect Content-Type header# Prevents IE/Chrome from interpreting files as different type
Referrer-Policy
# Don't send referrer
response.headers['Referrer-Policy'] = 'no-referrer'# Send only origin (no path)
response.headers['Referrer-Policy'] = 'origin'# Send full URL to same origin, origin to cross-origin
response.headers['Referrer-Policy'] = 'origin-when-cross-origin'# Strict: only HTTPS → HTTPS
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'# No referrer to less secure (HTTPS → HTTP)
response.headers['Referrer-Policy'] = 'no-referrer-when-downgrade'
Permissions-Policy
# Disable all features
response.headers['Permissions-Policy'] = (
'geolocation=(), microphone=(), camera=(), ''payment=(), usb=(), magnetometer=(), gyroscope=()'
)
# Allow specific features for self
response.headers['Permissions-Policy'] = (
'geolocation=(self), camera=(self)'
)
# Allow for specific origins
response.headers['Permissions-Policy'] = (
'geolocation=(self "https://maps.example.com")'
)
X-XSS-Protection (Legacy)
# Enable XSS filter (legacy browsers)
response.headers['X-XSS-Protection'] = '1; mode=block'# Note: Modern browsers rely on CSP instead# Still useful for older browsers