Django 生产环境如何正确配置 ALLOWED_HOSTS 防止主机头攻击?

文章导读
生产环境部署 Django 时,必须在 settings.py 中显式填写 ALLOWED_HOSTS 列表,只包含你信任的域名或 IP,这是防止主机头攻击最直接的防线。
📋 目录
  1. 配置步骤与最佳实践
  2. 原理简述
  3. 验证是否生效
  4. 常见坑与排查
  5. 参考来源
A A

生产环境部署 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 会拒绝所有请求。

Django 生产环境如何正确配置 ALLOWED_HOSTS 防止主机头攻击?

验证是否生效

使用 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