在云计算和内容分发网络(CDN)日益普及的今天,许多网站将应用服务器部署在 CloudFront、Cloudflare 或 Akamai 等 CDN 后面,以提升访问速度和抗压能力。然而,一个在开发者社区中持续引发讨论的安全问题也随之浮现:当应用运行在 CDN 之后、请求来源 IP 变为 CDN 共享 IP 时,Django 等框架中的 ALLOWED_HOSTS 设置是否还有必要?如果省略,会带来什么风险?

什么是 ALLOWED_HOSTS?为何它如此重要?

ALLOWED_HOSTS 是 Django 框架内置的一个安全配置项,用于验证 HTTP 请求头中的 Host 字段。当用户访问网站时,浏览器会自动发送 Host 头(例如 example.com),服务器通过该值判断请求是否属于自身管理的域名。如果 Host 头不在 ALLOWED_HOSTS 列表内,Django 会返回 400 Bad Request 错误,从而有效防止 HTTP Host 头攻击

这种攻击的核心在于:攻击者可以伪造 Host 头,使服务器误以为请求来自某个受信任的域名,进而绕过某些安全机制(例如密码重置链接生成、缓存投毒、CSRF 保护等)。即使网站部署在 CDN 之后,攻击者仍有可能通过直接访问源服务器 IP 或利用 CDN 的转发漏洞发送恶意请求。因此,ALLOWED_HOSTS 被视为 Web 应用的第一道防线。

CDN 环境下的特殊性:共享 IP 与 Host 头转发

当网站使用 CloudFront 等 CDN 时,源服务器接收到的请求来源 IP 通常是 CDN 节点的 IP 地址,而非真实用户 IP。同时,CDN 会保留原始请求的 Host 头并转发给源站(除非配置了自定义头部)。这意味着,如果 ALLOWED_HOSTS 仅设置为 CDN 分配的域名(例如 d1234.cloudfront.net),而用户通过你的业务域名 www.example.com 访问,则请求会被拒绝。

常见的做法是将 ALLOWED_HOSTS 设置为所有合法的业务域名,例如 ['www.example.com', 'api.example.com'],甚至可以包含 CDN 域名。但很多开发者认为,既然源服务器不对外暴露且所有流量都经过 CDN,那么 ALLOWED_HOSTS 似乎可以放宽——比如设置为 ['*'] 或直接跳过验证。这种想法是否安全?

风险分析:放宽 ALLOWED_HOSTS 的危险性

  1. 源服务器直接暴露:即使你认为源服务器不对外公开,IP 地址仍可能通过 DNS 记录泄露、历史扫描或误配置被攻击者发现。一旦攻击者绕过 CDN 直接访问源 IP,并发送伪造的 Host 头,他们可能发动缓存投毒、密码重置劫持等攻击。没有 ALLOWED_HOSTS 限制,服务器将无条件接受这类请求。

  2. CDN 配置漏洞:部分 CDN 可能允许用户自定义请求头部,或者存在转发规则配置错误,导致非预期的 Host 值被传递到源站。此时,若 ALLOWED_HOSTS 过于宽松,攻击者可以利用这些漏洞发起攻击。

  3. 内部网络攻击:如果应用部署在云 VPC 内部,其他服务或容器可能通过内网直接访问源站。这些内网请求的 Host 头可能不可控,如果没有验证,可能被恶意利用。

  4. 合规要求:许多安全标准(如 PCI DSS、SOC 2)明确要求对输入进行验证,包括 HTTP 头部。放宽 ALLOWED_HOSTS 可能导致合规审计失败。

最佳实践:在 CDN 环境下正确配置 ALLOWED_HOSTS

业界安全专家的共识是:即使使用 CDN,也应始终配置 ALLOWED_HOSTS 以下是具体建议:

  • 明确列出所有业务域名:将网站真实使用的所有域名(包括主站、子域名、API 域名)加入 ALLOWED_HOSTS。可同时包含 CDN 分配的域名(如 xxxx.cloudfront.net),以便健康检查或直接访问。
  • 不要使用通配符 *:除非你完全信任所有来源且能承受攻击风险,否则应避免全局通配符。即使使用通配符域名(如 *.example.com),也要确保其仅匹配受控子域。
  • 结合反向代理中间件:对于 Django,可以配合 SECURE_PROXY_SSL_HEADER 等设置,确保 Host 头来自可信代理。使用 django-cspdjango-axes 等扩展加强安全。
  • 限制源服务器网络访问:在云安全组或防火墙中,仅允许 CDN 节点的 IP 段访问源服务器的 80/443 端口,进一步降低直接攻击风险。
  • 定期审计:检查 CDN 配置中是否开启了“保留原始 Host 头”或“自定义头部”,确保转发规则正确。

结语

ALLOWED_HOSTS 并非多余的限制,而是应用安全的基本保障。在 CDN 环境下,虽然共享 IP 增加了网络层面的复杂性,但攻击面并未消失。正确配置此设置,配合网络隔离和输入验证,才能构建真正安全的后端服务。对于所有使用 Django 或其他类似框架(如 Flask、Express)的开发者,请记住:安全始于每一行配置,不要因为“觉得没什么问题”而留下可乘之机。