在經過代理、CDN、負載均衡的複雜網絡拓撲中,$_SERVER['REMOTE_ADDR'] 往往不是用戶真實 IP。本文系統梳理三大關鍵變量在**五種代理匿名級別**下的具體表現,並提供生產級獲取策略。
| 變量 | 含義 | 來源 |
|---|---|---|
REMOTE_ADDR | 直接連接 Web 服務器的客戶端 IP(最後一級代理或用戶) | TCP 連接層,不可偽造 |
HTTP_X_FORWARDED_FOR (XFF) | 代理鏈路 IP 列表:client, proxy1, proxy2... | 代理服務器添加的 HTTP 頭,可偽造 |
HTTP_VIA | 代理服務器標識信息(軟件名/版本/主機名) | 代理服務器添加 |
HTTP_CLIENT_IP | 部分代理/CDN 設置的客戶端 IP 頭 | 非標準,視具體設備而定 |
| 代理類型 | REMOTE_ADDR | HTTP_VIA | HTTP_X_FORWARDED_FOR | 隱匿效果 |
|---|---|---|---|---|
| 無代理 | 用戶真實 IP | 無/不顯示 | 無/不顯示 | 完全透明 |
| 透明代理 (Transparent) | 最後一級代理 IP | 代理 IP | 用戶真實 IP (多級代理時逗號分隔) | 暴露真實 IP,僅繞過訪問限制 |
| 匿名代理 (Anonymous) | 最後一級代理 IP | 代理 IP | 代理 IP (隱藏真實 IP,但暴露使用代理) | 隱藏真實 IP,但可被識別為代理流量 |
| 欺騙代理 (Distorting) | 代理 IP | 代理 IP | 隨機/偽造 IP | 隱藏真實 IP 並欺騙目標服務器 |
| 高匿代理 (Elite/High Anonymity) | 代理 IP | 無/不顯示 | 無/不顯示 | 完全偽裝為普通用戶,最難檢測 |
X-Forwarded-For: 1.2.3.4,**Web 應用層無法單憑 XFF 判斷真實 IP**。client, proxy1, proxy2,真實客戶端通常在**最左側**,需跳過內網/保留地址段(10.x、172.16-31.x、192.168.x、127.x、169.254.x)。# nginx.conf http 段
# 定義受信代理 IP 範圍(SLB、CDN 回源 IP、內部網關)
set_real_ip_from 10.0.0.0/8; # 內網/負載均衡
set_real_ip_from 172.16.0.0/12; # 內網
set_real_ip_from 100.64.0.0/10; # 運營商級 NAT (CGNAT)
set_real_ip_from 192.168.0.0/16; # 內網
# 添加具體 CDN/SLB IP 段,如:
# set_real_ip_from 1.2.3.0/24; # 阿里云 SLB
# set_real_ip_from 47.0.0.0/8; # 騰訊云 CLB
real_ip_header X-Forwarded-For; # 從此頭獲取真實 IP
real_ip_recursive on; # 遞歸查找:跳過受信代理,取第一個非受信 IP
# 可選:記錄原始 XFF 供審計
log_format main '$remote_addr - $realip_remote_addr [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
配置後,**PHP 直接使用 $_SERVER['REMOTE_ADDR'] 即為真實客戶端 IP**,無需複雜應用層邏輯。
function getRealIp(): string {
$trustedProxies = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16']; // 需與 Nginx 一致
$headers = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED'];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = array_map('trim', explode(',', $_SERVER[$header]));
foreach ($ips as $ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
}
// 兜底:REMOTE_ADDR(可能為內網代理 IP)
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
filter_var($ip, FILTER_VALIDATE_IP) 自動支持 IPv4/IPv6fc00::/7 (ULA)、fe80::/10 (Link-local)、::1/128 (Loopback)set_real_ip_from 支持 IPv6 CIDR黃金法則:**真實 IP 識別責任鏈:客戶端 → 邊緣代理 (CDN/SLB/WAF) → 應用負載均衡 → Web 服務器 (Nginx) → PHP**。**在 Nginx 層通過
real_ip_recursive解決**,PHP 層只做兜底與審計。任何嘗試在 PHP 中單獨解析 XFF 的方案在安全性上都是不完備的。