本文目录导读:

在 PHP 项目中处理多层 CDN(如 Cloudflare → 阿里云 CDN → 源站)时,需要通过逐层判断 HTTP 头部来获取真实访客 IP,以下是标准实现方案:
核心原理
CDN 通常在请求头中传递原始 IP:
X-Forwarded-For:最常用,可包含逗号分隔的多个IPX-Real-IP:部分CDN使用(如Nginx)CDN-Specific-IP:特定CDN的私有头(如 Cloudflare 的CF-Connecting-IP)
多层CDN解析策略
function getRealClientIP() {
// 1. 检查专用CDN头(优先)
$cdnHeaders = [
'HTTP_CF_CONNECTING_IP', // Cloudflare
'HTTP_X_FORWARDED_FOR', // 标准代理
'HTTP_X_REAL_IP', // Nginx代理
'HTTP_X_AKAMAI_EDGESERVERIP', // Akamai
'HTTP_TRUE_CLIENT_IP', // Cloudflare Enterprise
'HTTP_FASTLY_CLIENT_IP', // Fastly
'HTTP_INCAP_CLIENT_IP', // Incapsula
'HTTP_CLIENT_IP' // 通用
];
foreach ($cdnHeaders as $header) {
if (isset($_SERVER[$header]) && !empty($_SERVER[$header])) {
$ip = $_SERVER[$header];
// 2. 处理 X-Forwarded-For 多IP情况(从右到左排除可信代理)
if ($header === 'HTTP_X_FORWARDED_FOR') {
$ip = parseXForwardedFor($ip);
}
// 3. 验证IP有效性
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
// 4. 最终fallback到REMOTE_ADDR
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
/**
* 解析X-Forwarded-For多级IP
* 示例:X-Forwarded-For: client, proxy1, proxy2
* 策略:取最左侧有效公网IP(排除CDN节点IP)
*/
function parseXForwardedFor($headerValue) {
$ips = explode(',', $headerValue);
$ips = array_map('trim', $ips);
// 定义可信CDN节点IP段(根据实际CDN提供商配置)
$trustedProxies = [
'173.245.48.0/20', // Cloudflare
'103.21.244.0/22', // Cloudflare
'103.22.200.0/22', // Cloudflare
'103.31.4.0/22', // Cloudflare
'141.101.64.0/18', // Cloudflare
'108.162.192.0/18', // Cloudflare
'190.93.240.0/20', // Cloudflare
'188.114.96.0/20', // Cloudflare
'197.234.240.0/22', // Cloudflare
'198.41.128.0/17', // Cloudflare
'162.158.0.0/15', // Cloudflare
'104.16.0.0/12', // Cloudflare
'172.64.0.0/13', // Cloudflare
'131.0.72.0/22', // Cloudflare
// 阿里云CDN
'106.11.0.0/16',
'218.30.0.0/15',
// ... 其他CDN厂商IP段
];
// 从右向左扫描,跳过可信代理IP
for ($i = count($ips) - 1; $i >= 0; $i--) {
$ip = $ips[$i];
if (!isTrustedProxy($ip, $trustedProxies)) {
return $ip;
}
}
// 如果所有IP都是可信代理,返回最左侧
return $ips[0] ?? $_SERVER['REMOTE_ADDR'];
}
function isTrustedProxy($ip, $trustedProxies) {
foreach ($trustedProxies as $cidr) {
if (ipInCIDR($ip, $cidr)) {
return true;
}
}
return false;
}
/**
* CIDR匹配函数
*/
function ipInCIDR($ip, $cidr) {
list($subnet, $mask) = explode('/', $cidr);
if ((ip2long($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($subnet)) {
return true;
}
return false;
}
集成方案(最佳实践)
配置文件(config/cdn.php)
return [
'trusted_proxies' => [
// Cloudflare IP ranges
'173.245.48.0/20',
'103.21.244.0/22',
// ... 完整列表从CDN官网获取
// 阿里云CDN
'106.11.0.0/16',
// 自定义内网CDN
'10.0.0.0/8',
'172.16.0.0/12',
],
'ip_headers' => [
'CF-Connecting-IP',
'X-Real-IP',
'X-Forwarded-For',
'True-Client-IP',
],
];
中间件实现(Laravel示例)
namespace App\Http\Middleware;
use Closure;
class ResolveClientIP
{
public function handle($request, Closure $next)
{
$clientIP = $this->getClientIP($request);
$request->merge(['client_ip' => $clientIP]);
return $next($request);
}
private function getClientIP($request)
{
// Cloudflare优先
if ($request->hasHeader('CF-Connecting-IP')) {
return $request->header('CF-Connecting-IP');
}
// X-Forwarded-For
if ($request->hasHeader('X-Forwarded-For')) {
$ips = explode(',', $request->header('X-Forwarded-For'));
// 从右到左排除可信代理
foreach (array_reverse($ips) as $ip) {
$ip = trim($ip);
if (!$this->isTrustedProxy($ip)) {
return $ip;
}
}
}
return $request->ip();
}
private function isTrustedProxy($ip)
{
$proxies = config('cdn.trusted_proxies');
foreach ($proxies as $cidr) {
if ($this->ipInCIDR($ip, $cidr)) {
return true;
}
}
return false;
}
}
测试验证方法
测试脚本
// test.php
$_SERVER = [
'REMOTE_ADDR' => '1.2.3.4',
'HTTP_X_FORWARDED_FOR' => '203.0.113.5, 198.51.100.1, 192.0.2.1',
'HTTP_CF_CONNECTING_IP' => '203.0.113.5',
];
echo "Client IP: " . getRealClientIP();
// 输出: 203.0.113.5 (因为X-Forwarded-For最左侧为203.0.113.5)
使用curl模拟测试
# 模拟三层CDN
curl -H "X-Forwarded-For: 真正的公网IP, CDN1节点IP, CDN2节点IP" \
-H "CF-Connecting-IP: 真正的公网IP" \
https://yourdomain.com/api/check-ip.php
安全注意事项
- 不要信任REMOTE_ADDR:在多CDN环境下,它通常只代表最后一层CDN节点
- 定期更新CDN IP段:从各CDN厂商获取最新IP范围
- 考虑IP伪造风险:如果HTTP头可被伪造,需要验证请求是否真的经过CDN
- 使用HTTPS:防止中间人篡改头部信息
- 记录请求链路:建议记录完整IP链用于调试
生产环境配置示例
# Nginx 配置示例
server {
set_real_ip_from 10.0.0.0/8; # 内网CDN
set_real_ip_from 173.245.48.0/20; # Cloudflare
real_ip_header X-Forwarded-For;
real_ip_recursive on; # 关键:开启递归查找
}
通过这种分层策略,可以准确获取经过多层CDN代理后的真实访客IP,同时避免伪造IP攻击,建议在框架层面统一实现并缓存结果,避免每次请求重复计算。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播