$_SERVER['HTTP_HOST']不可靠,因它直接取自可被攻击者伪造的HTTP Host头,易导致开放重定向、缓存污染或SSRF;应优先硬编码可信域名或通过Nginx安全透传X-Real-Host。

为什么 $_SERVER['HTTP_HOST'] 不可靠
它直接取自 HTTP 请求头的 Host 字段,攻击者可任意伪造。比如用 curl 手动发请求:curl -H "Host: evil.com" https://your-site.com/,此时 $_SERVER['HTTP_HOST'] 就会变成 evil.com —— 一旦你用它拼接跳转链接、生成资源 URL 或写入日志,就可能引发开放重定向、缓存污染甚至 SSRF。
从 Web 服务器配置中硬编码可信域名
最稳妥的方式是绕开所有动态输入,直接在 PHP 中声明你认可的域名。适用于 Nginx/Apache 已明确绑定到单域名或有限域名的场景:
- 在入口文件(如
index.php)顶部定义:define('TRUSTED_DOMAIN', 'example.com'); - 若需支持 www 和非 www,可统一规范化:
$domain = $_SERVER['HTTP_HOST'] === 'www.example.com' ? 'example.com' : $_SERVER['HTTP_HOST'];,但仅限你确认服务器只响应这两个 Host 的前提下 - 不要依赖
$_SERVER['SERVER_NAME']:它来自 Apache 的ServerName指令,但在虚拟主机共用 IP 时可能不准确;Nginx 默认不设置该值,PHP 中常为空
通过反向代理头识别真实域名(如 Nginx + PHP-FPM)
当使用 Nginx 做反向代理时,可让 Nginx 把原始 Host 写入一个自定义请求头(如 X-Real-Host),再在 PHP 中读取。关键点在于:这个头必须由 Nginx 强制注入,不能被客户端传递覆盖。
- Nginx 配置中加:
proxy_set_header X-Real-Host $host;(注意不是$http_host) - PHP 中安全读取:
$domain = $_SERVER['HTTP_X_REAL_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'default.com'; - 务必在 Nginx 中禁用客户端传入该头:
underscores_in_headers off;,并避免使用带下划线的 header 名(部分 CGI 模式会丢弃) - 不要信任
X-Forwarded-Host:它常被客户端伪造,除非你在前端严格过滤并重写
HTTPS 下的协议与端口一致性处理
获取域名后,若要构造完整 URL(比如生成 Open Graph 标签或 API 回调地址),不能只拼 $_SERVER['HTTP_HOST'],否则可能混用 http/https 或错误端口。
立即学习“PHP免费学习笔记(深入)”;
- 判断协议:
$scheme = $_SERVER['HTTPS'] === 'on' ? 'https' : 'http'; - 判断端口(仅当非标准端口时才显式添加):
$port = ($_SERVER['HTTPS'] === 'on' && $_SERVER['SERVER_PORT'] != 443) || ($_SERVER['HTTPS'] !== 'on' && $_SERVER['SERVER_PORT'] != 80) ? ':' . $_SERVER['SERVER_PORT'] : ''; - 组合结果:
$origin = $scheme . '://' . TRUSTED_DOMAIN . $port;
真正难的不是“怎么取”,而是确认哪个环节可控、哪个环节已被外部污染——很多线上问题,根源是开发时假设了 Host 头可信,而运维侧又没做头过滤。











