生产环境部署 Django 时,必须在 settings.py 中显式填写 ALLOWED_HOSTS 列表,只包含你信任的域名或 IP,这是防止主机头攻击最直接的防线。
先说结论:ALLOWED_HOSTS 是 Django 的安全白名单,生产环境严禁留空或使用通配符,需精确匹配业务域名。
- 先判断:确认 DEBUG 已设为 False,否则该设置不生效。
- 优先做:在 settings.py 中填入完整域名,如 ["www.example.com", "example.com"]。
- 再验证:使用非法 Host 头请求接口,确认返回 400 或 403 状态码。
配置步骤与最佳实践
找到项目 settings.py,定位到 ALLOWED_HOSTS 变量。生产环境建议通过环境变量管理,避免敏感配置硬编码:
import os
# 推荐:从环境变量读取,本地开发可设默认值
ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",")
# 或者显式指定生产域名
# ALLOWED_HOSTS = ["www.yourdomain.com", "yourdomain.com"]如果需要通过 IP 直接访问,将 IP 地址也加入列表,但不要仅依赖 IP。修改配置后需重启 Gunicorn、uWSGI 或 Django 服务才能生效。部署前务必备份 settings.py,若配置错误导致服务不可用,可快速还原。
原理简述
Django 依赖 HTTP 请求头中的 Host 字段来生成绝对 URL 或验证请求来源。如果未限制该字段,攻击者可以构造恶意的 Host 头,诱导 Django 生成指向攻击者服务器的链接,常用于密码重置链接投毒或缓存欺骗。
官方文档明确指出,当 DEBUG=False 时,如果不设置 ALLOWED_HOSTS,Django 会拒绝所有请求。
验证是否生效
使用 curl 命令模拟非法 Host 头请求,观察响应状态:
curl -H "Host: evil.com" http://your-server-ip/若配置正确,应返回 400 Bad Request 或 403 Forbidden。使用合法域名请求应正常返回 200:
curl -H "Host: www.yourdomain.com" http://your-server-ip/常见坑与排查
1. 通配符风险:避免使用 ["*"],这相当于关闭了防护,任何 Host 头都会被接受。
2. 代理场景配置:如果前端有 Nginx 或负载均衡,需确保代理服务器透传原始 Host 头。在 Nginx 配置中检查是否包含 proxy_set_header Host $host;。Django 默认校验接收到的 Host 头,而非 X-Forwarded-Host,除非显式开启 USE_X_FORWARDED_HOST(一般不建议)。
3. 本地调试:本地开发时通常填 ["localhost", "127.0.0.1"],不要直接把生产配置复制到本地而不修改。
参考来源
- Django 官方文档 - Security guide: https://docs.djangoproject.com/en/stable/topics/security/#host-headers-virtual-hosting
- Django 官方文档 - Settings: https://docs.djangoproject.com/en/stable/ref/settings/#allowed-hosts