bigywater.tech
Django · 121

SecurityMiddleware 的安全响应头

Django 的安全响应头有多少是默认就发的?哪些要自己打开?这篇用 Client 直接看响应头,再用 manage.py check --deploy 给一个最小项目「体检」,最后试一下 Django 6 新增的 CSP 中间件。

4 个默认头
nosniff、Referrer-Policy、COOP、X-Frame-Options 无需任何设置就有
HSTS 与 CSP 默认没有
要分别配置 SECURE_HSTS_SECONDS 与 SECURE_CSP
4 → 1
check --deploy 的警告条数:实验默认设置 → 加固后

默认的响应头

实测 · 本机执行输出
  X-Content-Type-Options             nosniff
  Referrer-Policy                    same-origin
  Cross-Origin-Opener-Policy         same-origin
  X-Frame-Options                    DENY
  Strict-Transport-Security          (没有)
  Content-Security-Policy            (没有)
  Content-Security-Policy-Report-Only (没有)

注意 X-Frame-Options 来自 XFrameOptionsMiddleware,不是 SecurityMiddleware;两个都要在 MIDDLEWARE 里。

HSTS

实测 · 本机执行输出
  https 请求   status 200  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  http 请求    status 200  Strict-Transport-Security: (没有)

HSTS 告诉浏览器「以后只用 HTTPS 访问这个域名」,只在 HTTPS 响应上发才有意义。浏览器收到后的行为发生在浏览器里,本文没有验证。开 preload 之前要确认所有子域名都能走 HTTPS,这是设计上的提醒,本文没有做实验。

SSL 重定向

实测 · 本机执行输出
  http GET /          → 301  Location: https://localhost/
  http GET /healthz/  → 404  Location: (无)

check --deploy

实测 · 本机执行输出
  默认: 4 条警告 ['security.W003', 'security.W004', 'security.W008', 'security.W009']
  加固后: 1 条警告 ['security.W003']
  默认时各警告的含义(每条第一行):
    security.W003  You don't appear to be using Django's built-in cross-site request forgery protection via the mi
    security.W004  You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served onl
    security.W008  Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over 
    security.W009  Your SECRET_KEY has less than 50 characters, less than 5 unique characters, or it's prefixed wi

这个命令只检查设置,不检查你的服务器配置。加固后剩下的 W003 是因为我的最小中间件列表里没有 CsrfViewMiddleware,真实项目里不会出现。

内置 CSP

实测 · 本机执行输出
  X-Content-Type-Options             nosniff
  Referrer-Policy                    same-origin
  Cross-Origin-Opener-Policy         same-origin
  X-Frame-Options                    DENY
  Strict-Transport-Security          (没有)
  Content-Security-Policy            default-src 'self'; frame-ancestors 'none'
  Content-Security-Policy-Report-Only default-src 'self'; img-src https:

Django 6 之前要靠第三方包(django-csp 等)。CSP 策略写错会拦掉页面自己的脚本和样式,所以先用 SECURE_CSP_REPORT_ONLY 观察,本文只验证了响应头的生成,没有验证浏览器的拦截与上报。

分步演示

安全响应头
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Python 3.14.7 / Django 6.1.1(默认用 SQLite,其它数据库会在文中注明),用 django.test.Client 或真实的本机服务器进程实测;计时用 time.perf_counter,数字每次运行会有小幅抖动。django.test.Client 请求最小项目;secure=True 模拟 HTTPS;check --deploy 用 DEBUG=False、ALLOWED_HOSTS=["example.com"]
    • 没有验证:浏览器里对 HSTS / CSP 的实际处理、CSP 的 nonce 用法、Permissions-Policy 之类 Django 没有内置的头、反向代理对响应头的改写、SECURE_CROSS_ORIGIN_OPENER_POLICY 的其它取值
    京ICP备2026067502号-1京公网安备11010502063487号