kavo

使用 Cloudlfare 获取 IPV4 以及 IPV6 的测试

前言,最近 Cloudflare 的 IP 获取有些变化,导致获取用户的 IP 出现一些问题,经过测试记录一下

以下解释以 PHP 中的 $_SERVER 中的值为例

一般来说,在不使用反向代理的情况下,我们通常使用 REMOTE_ADDR 获取客户端的 IP

REMOTE_ADDR

但是在使用了反向代理之后,我们使用 HTTP_X_FORWARDED_FOR,因为 REMOTE_ADDR 已经是反向代理服务器的 IP

HTTP_X_FORWARDED_FOR

但是众所周知 HTTP_X_FORWARDED_FOR 值是可以伪造的,而它可以以逗号为连接的多个值,所以很不安全

这时候,在使用 Cloudflare 的情况下,Cloudflare 设置 HTTP_CF_CONNECTING_IP 获取 IP

HTTP_CF_CONNECTING_IP

坑来了,注意以下测试数据

细心的管理员会发现,有些用户的 IP 通过 HTTP_X_FORWARDED_FOR 和 HTTP_CF_CONNECTING_IP 获取均为内网 IP ,例如:251.120.126.7

经过推测,应该是电信运营商为用户分配了 IPV6 地址,但同时也分配了 IPV4 地址,只不过为了节省 IP 资源,IPV4 设置为内网 IP ,这时候 HTTP_CF_CONNECTING_IP 值就准确了

怎么办呢?

这个时候 Cloudfalre 请求中设置的 HTTP_CF_CONNECTING_IPV6 就要登场了,因为在以上 HTTP_CF_CONNECTING_IP 为内网地址的情况下,HTTP_CF_CONNECTING_IPV6  会显示真实的 IPV6 地址

HTTP_CF_CONNECTING_IPV6 

所以,如果你有相关业务需求,你可以编写一个函数,以下以 Laravel 框架公共函数来处理。注意,这是在使用 Cloudflare 的情况下,其他 CDN 服务商需要参考对应文档

function getClientIp()
{
    $request = request();

    // 尝试获取IPv4地址
    $ipv4 = $request->header('CF-Connecting-IP');
    if ($ipv4 && filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        return $ipv4;
    }

    // 如果IPv4无效,尝试获取IPv6地址
    $ipv6 = $request->header('CF-Connecting-IPv6');
    if ($ipv6 && filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
        return $ipv6;
    }

    // 如果Cloudflare的头部都无效,尝试使用X-Forwarded-For
    $forwardedIp = $request->header('X-Forwarded-For');
    if ($forwardedIp) {
        $ips = explode(',', $forwardedIp);
        $firstIp = trim($ips[0]);
        if (filter_var($firstIp, FILTER_VALIDATE_IP)) {
            return $firstIp;
        }
    }

    // 最后,使用Laravel的getClientIp方法
    return $request->getClientIp();
}

 如果你没有使用任何 php 框架,你可以使用以下函数,参数 $includeIpv6  用于是否启用 IPV6

function getClientIp($includeIpv6 = 0)
{
    // 尝试获取Cloudflare的IPv4地址
    if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
        $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip;
        }
    }

    // 如果includeIpv6为真,并且IPv4无效,尝试获取Cloudflare的IPv6地址
    if ($includeIpv6 && isset($_SERVER['HTTP_CF_CONNECTING_IPV6'])) {
        $ip = $_SERVER['HTTP_CF_CONNECTING_IPV6'];
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return $ip;
        }
    }

    // 尝试使用X-Forwarded-For
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        foreach ($ips as $ip) {
            $ip = trim($ip);
            if ($includeIpv6) {
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            } else {
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                    return $ip;
                }
            }
        }
    }

    // 尝试使用其他常见的服务器变量
    $ipSources = ['HTTP_CLIENT_IP', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'];
    foreach ($ipSources as $source) {
        if (isset($_SERVER[$source])) {
            $ip = $_SERVER[$source];
            if ($includeIpv6) {
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            } else {
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                    return $ip;
                }
            }
        }
    }

    // 如果所有方法都失败,返回null或者一个默认IP
    return null; // 或者返回一个默认IP,比如 '0.0.0.0'
}

 

最后感谢 Cloudflare ,致敬!

 

posted on 2024-10-21 17:24  下雨天唱情歌  阅读(68)  评论(0编辑  收藏  举报

导航