在云计算和内容分发网络(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 的危险性
-
源服务器直接暴露:即使你认为源服务器不对外公开,IP 地址仍可能通过 DNS 记录泄露、历史扫描或误配置被攻击者发现。一旦攻击者绕过 CDN 直接访问源 IP,并发送伪造的
Host头,他们可能发动缓存投毒、密码重置劫持等攻击。没有ALLOWED_HOSTS限制,服务器将无条件接受这类请求。 -
CDN 配置漏洞:部分 CDN 可能允许用户自定义请求头部,或者存在转发规则配置错误,导致非预期的
Host值被传递到源站。此时,若ALLOWED_HOSTS过于宽松,攻击者可以利用这些漏洞发起攻击。 -
内部网络攻击:如果应用部署在云 VPC 内部,其他服务或容器可能通过内网直接访问源站。这些内网请求的
Host头可能不可控,如果没有验证,可能被恶意利用。 -
合规要求:许多安全标准(如 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-csp或django-axes等扩展加强安全。 - 限制源服务器网络访问:在云安全组或防火墙中,仅允许 CDN 节点的 IP 段访问源服务器的 80/443 端口,进一步降低直接攻击风险。
- 定期审计:检查 CDN 配置中是否开启了“保留原始 Host 头”或“自定义头部”,确保转发规则正确。
结语
ALLOWED_HOSTS 并非多余的限制,而是应用安全的基本保障。在 CDN 环境下,虽然共享 IP 增加了网络层面的复杂性,但攻击面并未消失。正确配置此设置,配合网络隔离和输入验证,才能构建真正安全的后端服务。对于所有使用 Django 或其他类似框架(如 Flask、Express)的开发者,请记住:安全始于每一行配置,不要因为“觉得没什么问题”而留下可乘之机。