最可靠方法是先解析域名获取IP,再校验是否属于RFC定义的内网IP段。需用dns_get_record()兼容IPv6,结合filter_var()验证IP有效性,并手动比对127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、100.64.0.0/10等保留地址段。
PHP判断域名是否为内网地址的可靠方法
直接用 filter_var() + FILTER_VALIDATE_IP 验证解析后的 IP 最稳妥。不能只靠域名字符串匹配(比如 "localhost" 或 "test.local"),因为真实请求可能通过 hosts 绑定、反向代理或 DNS 解析指向内网 IP,而域名本身看不出端倪。
关键步骤是:先 gethostbyname() 或 dns_get_record() 获取 A 记录 IP,再对 IP 做内网段校验。注意 gethostbyname() 不支持 IPv6,若需兼容,优先用 dns_get_record($domain, DNS_A + DNS_AAAA) 并分别处理。
常用内网 IP 段的判断逻辑与代码片段
内网地址不是“黑名单域名”,而是 RFC 1918 / 6598 定义的保留 IP 段。PHP 没有内置函数直接判断,需手动比对。以下覆盖绝大多数情况:
-
127.0.0.0/8(本地回环) 10.0.0.0/8-
172.16.0.0/12(即 172.16–172.31) 192.168.0.0/16-
100.64.0.0/10(CGNAT,越来越常见)
示例函数:
立即学习“PHP免费学习笔记(深入)”;
function isPrivateIp($ip) {
if (!filter_var($ip, FILTER_VALIDATE_IP)) return false;
$ipLong = ip2long($ip);
$ranges = [
['127.0.0.0', '127.255.255.255'],
['10.0.0.0', '10.255.255.255'],
['172.16.0.0', '172.31.255.255'],
['192.168.0.0', '192.168.255.255'],
['100.64.0.0', '100.127.255.255'],
];
foreach ($ranges as [$start, $end]) {
if ($ipLong >= ip2long($start) && $ipLong <= ip2long($end)) {
return true;
}
}
return false;
}
HTTP 请求头中 Host 域名不等于服务端实际访问地址
用户可任意伪造 Host 头,$_SERVER['HTTP_HOST'] 或 $_SERVER['SERVER_NAME'] 不能直接用于安全判断。尤其在 Nginx/Apache 反向代理场景下,真实客户端 IP 来自 X-Forwarded-For,但该头也可被伪造 —— 所以必须结合可信代理配置(如 Nginx 的 set_real_ip_from)和 REMOTE_ADDR 校验。
如果你要过滤“来自内网的请求”,真正该检查的是:$_SERVER['REMOTE_ADDR'](经真实 IP 修复后),而不是域名本身。