CloudFlare并通过PHP记录访问者IP地址


82

我正在尝试跟踪和记录使用PHP$_SERVER['REMOTE_ADDR']来访问我的网站的用户/访问者。PHP中IP地址跟踪的一种典型方法。

但是,我正在使用CloudFlare进行缓存等,并以CloudFlare的方式接收其IP地址:

108.162.212。*-108.162.239。*

在仍然使用CloudFlare的同时检索实际用户/访问者IP地址的正确方法是什么?

Answers:


239

云耀斑可用的其他服务器变量是:

$_SERVER["HTTP_CF_CONNECTING_IP"] 真正的访客IP地址,这就是您想要的

$_SERVER["HTTP_CF_IPCOUNTRY"] 访客所在国家

$_SERVER["HTTP_CF_RAY"]

$_SERVER["HTTP_CF_VISITOR"] 这可以帮助您知道它的http还是https

您可以像这样使用它:

if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
  $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}

如果这样做,并且访问IP地址的有效性很重要,则可能需要验证$_SERVER["REMOTE_ADDR"]包含一个实际有效的cloudflare IP地址,因为如果有人能够直接连接到服务器IP,则任何人都可以伪造该报头。


15
+1用于将REMOTE_ADDR替换为真实IP,因此不需要其他代码修改。
aalaap 2014年

11
如果安全性很重要,则应检查该请求是否来自Cloudflare IP范围(cloudflare.com/ips)。例如,在这个Joomla中!插件:github.com/piccaso/joomla-cf/blob/master/cf/cf.php
Florian Fida

Cloudflare的网站上也列出了此代码。support.cloudflare.com/hc/en-us/articles/...
C0nw0nk

最佳答案,但也包括HTTP_CF_IPCOUNTRY在内的荣誉,我以前从未遇到过。
大卫·贝尔

http_cf_connecting_ip有时会给出类似的信息:2a01:6500:a043:33a6:b36a:7259:4de5:2500知道为什么吗?
迈克尔

15

更新:CloudFlare发布了一个mod_cloudflare针对Apache的模块,该模块将记录并显示实际的访客IP地址,而不是cloudflare访问的IP地址!https://www.cloudflare.com/resources-downloads#mod_cloudflare(回答:olimortimer

如果您无权访问apache运行时,则可以使用以下脚本,这将允许您检查连接是否通过cloudflare并获取用户ip。

我正在重写我用于另一个问题“ CloudFlare DNS /直接IP标识符”的答案

Cloudflare的ips是公开存储的,因此您可以在此处查看它们然后检查ip是否来自cloudflare(这将使我们能够从http标头中获取真实ip HTTP_CF_CONNECTING_IP)。

如果您使用它来禁用所有非cf连接,反之亦然,我建议您有一个单独的php脚本文件,该文件在每个其他脚本(例如common.php或pagestart.php等)之前被调用。

function ip_in_range($ip, $range) {
    if (strpos($range, '/') == false)
        $range .= '/32';

    // $range is in IP/CIDR format eg 127.0.0.1/24
    list($range, $netmask) = explode('/', $range, 2);
    $range_decimal = ip2long($range);
    $ip_decimal = ip2long($ip);
    $wildcard_decimal = pow(2, (32 - $netmask)) - 1;
    $netmask_decimal = ~ $wildcard_decimal;
    return (($ip_decimal & $netmask_decimal) == ($range_decimal & $netmask_decimal));
}

function _cloudflare_CheckIP($ip) {
    $cf_ips = array(
        '199.27.128.0/21',
        '173.245.48.0/20',
        '103.21.244.0/22',
        '103.22.200.0/22',
        '103.31.4.0/22',
        '141.101.64.0/18',
        '108.162.192.0/18',
        '190.93.240.0/20',
        '188.114.96.0/20',
        '197.234.240.0/22',
        '198.41.128.0/17',
        '162.158.0.0/15',
        '104.16.0.0/12',
    );
    $is_cf_ip = false;
    foreach ($cf_ips as $cf_ip) {
        if (ip_in_range($ip, $cf_ip)) {
            $is_cf_ip = true;
            break;
        }
    } return $is_cf_ip;
}

function _cloudflare_Requests_Check() {
    $flag = true;

    if(!isset($_SERVER['HTTP_CF_CONNECTING_IP']))   $flag = false;
    if(!isset($_SERVER['HTTP_CF_IPCOUNTRY']))       $flag = false;
    if(!isset($_SERVER['HTTP_CF_RAY']))             $flag = false;
    if(!isset($_SERVER['HTTP_CF_VISITOR']))         $flag = false;
    return $flag;
}

function isCloudflare() {
    $ipCheck        = _cloudflare_CheckIP($_SERVER['REMOTE_ADDR']);
    $requestCheck   = _cloudflare_Requests_Check();
    return ($ipCheck && $requestCheck);
}

// Use when handling ip's
function getRequestIP() {
    $check = isCloudflare();

    if($check) {
        return $_SERVER['HTTP_CF_CONNECTING_IP'];
    } else {
        return $_SERVER['REMOTE_ADDR'];
    }
}

要使用脚本,它非常简单:

$ip = getRequestIP();
$cf = isCloudflare();

if($cf) echo "Connection is through cloudflare: <br>";
else    echo "Connection is not through cloudflare: <br>";

echo "Your actual ip address is: ". $ip;
echo "The server remote address header is: ". $_SERVER['REMOTE_ADDR'];

该脚本将显示您的真实IP地址,以及请求是否为CF!


这是正确的答案,但是请记住,您需要定期更新IP。上面的代码中的当前代码已经无效,因此代码将失败。您可以在此处获得最新的IP:cloudflare.com/ips 理想情况下,您应该将它们存储在文件中,以便只需要更新外部文件甚至更好,就可以定期从此处获取它们:cloudflare.com/ips-v4
rafark

11

自问及回答此问题以来,CloudFlare已mod_cloudflare针对Apache发布,该日志记录并显示实际的访问者IP地址,而不是CloudFlare地址:

https://www.cloudflare.com/resources-downloads#mod_cloudflare


2019-他们不再支持mod_cloudflare,但可以使用。有个新的名字mod_remoteip。参考:support.cloudflare.com/hc/en-us/articles/…–
sinaza,

@sinaza可能最好创建一个新答案,因为我的答案mod_cloudflare来自4年前
olimortimer

@sjagr关于您的编辑,它们是不正确的-正如我最初发布的那样,CloudFlare实际上是Cloudflare
olimortimer

10

Cloudflare将一些其他请求标头发送到您的服务器,其中包括CF-Connecting-IP我们可以$user_ip使用以下简单的单行存储到的请求标头:

$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"])?$_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);

问题在于这只是一个简单的标头,因此任何人都可以将其设置为所需的任何IP,这是一个巨大的安全漏洞。
rafark

@rafark如果服务器配置正确且位于Cloudflare后面,则不会。
塞南

当然是。这本身就是一个很好的解决方案,但仍应在使用HTTP_CF_CONNECTING_IP之前进行检查,例如Callum的回答
rafark

@rafark我也同意,但是大量的PHP代码已经以另一种形式出现在您的Apache配置中(我希望),并且该代码的目的是为了便于调试,并且如果攻击者可以访问您的调试环境,我认为您还有更多重要的问题要处理。
塞南

2

很难将HTTP_CF_CONNECTING_IP转换为REMOTE_ADDR。因此,您可以使用apache(.htaccess)自动添加。这样您就不必考虑$_SERVER['REMOTE_ADDR']所有PHP脚本中的值是否正确。

.htaccess代码

php_value auto_prepend_file "/path/to/file.php"

php代码(file.php)

<?php

define('CLIENT_IP', isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR']);

在这里了解更多


1

HTTP_CF_CONNECTING_IP仅在使用cloudflare时有效,也许您转移站点或删除cloudflare会忘记该值,因此请使用此代码。

$ip=$_SERVER["HTTP_CF_CONNECTING_IP"];
if (!isset($ip)) {
  $ip = $_SERVER['REMOTE_ADDR'];
}


0

使用CloudFlare时,服务器和用户之间的所有请求都将通过CloudFlare服务器进行路由。

在这种情况下,有两种获取用户的真实IP地址的方法:

  1. 通过CloudFlare服务器添加的额外服务器头
  2. 在您的服务器上添加一个CloudFlare Apache / NGINX模块。

方法1:通过额外的服务器头获取IP

您可以使用以下代码获取用户的IP地址:

$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"]) $_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);

运作方式如何?

CloudFlare在请求中添加了一些额外的服务器变量,如下所示:

$_SERVER["HTTP_CF_CONNECTING_IP"] -用户的真实IP地址

$_SERVER["HTTP_CF_IPCOUNTRY"] -用户的ISO2国家

$_SERVER["HTTP_CF_RAY"] 用于登录目的的特殊字符串

在上面的代码中,我们正在检查是否$_SERVER["HTTP_CF_CONNECTING_IP"]设置了。如果存在,我们将认为这是用户的IP地址,否则我们将使用默认代码作为$_SERVER['REMOTE_ADDR']

方法2:在服务器上安装Cloudflare模块

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.