Django 上线前的安全自查:五个设置项和一条命令

代码写完、功能测通,很多人把开发环境的 settings 原样搬上服务器——DEBUG 还开着,ALLOWED_HOSTS 还是 '*',HTTPS 证书挂上了但应用层一个字没改。这些配置在本地确实无害,上了生产就是另一回事:它们分别对应报错页泄密、Host 头攻击、重定向死循环、CSRF 403 这几类经典事故。这篇文章把上线前真正要过一遍的安全设置理清楚,最后有一条自动检查命令兜底。
DEBUG=True 时,任何未处理异常都会渲染一个详细的调试页:完整堆栈、本地变量、以及当前生效的全部 settings。官方对此做过过滤——名字里含 API、KEY、PASS、SECRET、SIGNATURE、TOKEN 的配置会被自动打码(部分匹配)。但这个过滤不是银弹:文件路径、数据库结构、配置选项照样暴露,给攻击者递情报;如果某个敏感配置的名字没沾上面这些词,它会原文打印。另外 DEBUG=True 时 Django 会把执行过的每一条 SQL 记在内存里,生产流量下就是内存泄漏。
修法是环境变量优先,一行就够:
默认设为 1 是为了本地零配置;生产环境的部署清单里显式传 DEBUG=0。这里有个经典坑:环境变量传了,settings 里却没读这行——防线等于没修。传了就必须读,最好再配一条配置类的 sanity 测试兜底。
先说功能层面:DEBUG=False 时必须正确配置 ALLOWED_HOSTS,否则所有请求都会返回 400。
再说安全层面,这是它更重要的职责:校验 HTTP 请求里的 Host 头。Django 里所有用 request.get_host() 构造绝对 URL 的地方——密码重置邮件、canonical 链接、重定向、sitemap——都依赖这道校验。设成 '*' 等于放弃校验,典型攻击是密码重置投毒:攻击者提交重置请求时伪造 Host 头,用户收到的重置邮件里,链接域名已经换成了攻击者控制的站点,点进去就是假表单收凭据;前面有缓存层时,Host 头被用作缓存键,还能造成缓存投毒。Django 1.4.2 之前正因不校验 Host 头出过 CVE-2012-4520,ALLOWED_HOSTS 这个配置就是为此而生。
所以生产上只写显式域名,不写通配:
需要覆盖子域时,用 .example.com 这种写法同时匹配主域和全部子域,比逐个列省事,但前提是这些子域确实都归你管——子域被攻破时,过宽的白名单就是后门。
还有一个绕过校验的暗坑:代码里直接读 request.META['HTTP_HOST'] 会完全绕过 ALLOWED_HOSTS 的保护。敏感 URL 的域名永远从配置取,不从请求头取。
证书上线不等于应用层就绪。SECURE_SSL_REDIRECT = True 会让 Django 把所有 http 请求跳转到 https。但典型生产架构是 Caddy 或 nginx 在前面终结 TLS,Django 看到的每个请求都是 http——不配下面第二行,就是无限重定向循环:
第二行要满足前提才能加:前面的代理是自己控制的、确实会设置 X-Forwarded-Proto 并清洗客户端伪造的同名头。这个头默认客户端可伪造,信任错对象,等于把「这个请求是不是 https」的判断权交给请求方。顺带一提:如果前面的 Caddy/nginx 已经默认做了 http→https 重定向,应用层这行可以不重复——但 cookie 的 secure 标志仍然要设,两道各管各的。
HSTS(SECURE_HSTS_SECONDS,默认 0)让浏览器记住「这个域名只走 https」,期间用户输入 http 也会被浏览器强制改写。注意它是粘性配置:一旦下发,想回退 http 要等过期,所以只在 HTTPS 链路稳定后再设;includeSubDomains 只在所有子域都 https 就绪时才开。Cookie 侧把 SESSION_COOKIE_SECURE 和 CSRF_COOKIE_SECURE 设为 True,会话凭据就只在 https 传输。
Django 4.0 起 CSRF 校验参考 Origin 头,CSRF_TRUSTED_ORIGINS 的值必须带协议:写 https://example.com,不能只写域名;旧的点开头写法 .example.com 也要改成 https://*.example.com。写法不对系统检查会直接提示。
最常见的踩法在协议切换时:站点从 http 切到 https 之后,后台登录、表单提交突然全部 403 CSRF——原因就是 Origin 变了而信任列表没跟上或格式不对。改完配一条冒烟:浏览器里真实登录一次、提交一次带 CSRF 的表单,比只看 curl 返回码可靠。
以上这些,Django 官方内置了一条自动检查,把部署检查清单里的安全项逐个过一遍并输出警告:
每个警告都值得当 blocker 处理,而且建议放进 CI 当测试跑——配置漂移往往发生在「后来有人改 settings」的时刻,靠人记清单不如靠门禁。补充一条新动态:Django 6.0 起内置了 CSP(内容安全策略)支持,通过 SECURE_CSP 配置加中间件启用,官方提供 report-only 模式——先只上报不拦截,观察日志清了再切强制,是给 XSS 防线加码的低风险路径。
这五个设置项加一条命令,覆盖的是 Django 生产安全里「改配置就能修好」的那部分;改配置修不好的(代码层漏洞、依赖漏洞),下一道防线再说。上线前把这篇文章的清单过一遍,胜过出事后排查一晚上。
#Django #Web安全 #Python #后端开发 #生产部署 #程序员