CloudFlare и регистрация IP-адресов посетителей через PHP

Я пытаюсь отслеживать и регистрировать пользователей / посетителей, которые получают доступ к моему сайту с помощью PHP $_SERVER['REMOTE_ADDR'] сделать это. Типичный метод для отслеживания IP-адресов в PHP.

Тем не менее, я использую CloudFlare для кэширования и тому подобное и получаю их IP-адреса как CloudFlare:

108.162.212. * - 108.162.239. *

Каков будет правильный метод получения фактического IP-адреса пользователя / посетителя при использовании CloudFlare?

13 ответов

Решение

Дополнительные серверные переменные, которые доступны для облачной вспышки:

$_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"] содержит действительный действительный IP-адрес cloudflare, потому что любой может подделать заголовок, если он сможет напрямую подключиться к IP-адресу сервера.

Я переписываю свой ответ, который я использовал для другого вопроса " CloudFlare DNS / прямой IP-идентификатор"

IP-адреса Cloudflare хранятся в открытом доступе, поэтому вы можете просмотреть их здесь, а затем проверить, является ли IP-адрес облачным (это позволит нам получить реальный IP-адрес из заголовка http 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 "Cloudflare :D<br>";
else    echo "Not cloudflare o_0";

echo "Your actual ip address is: ". $ip;

Этот скрипт покажет вам реальный IP-адрес, и если запрос CF или нет!

Cloudflare отправляет дополнительные заголовки запроса на ваш сервер, включая CF-Connecting-IP который мы можем хранить в $user_ipесли определено, используя этот простой однострочный:

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

Поскольку этот вопрос был задан и получен ответ, CloudFlare выпустила mod_cloudflare для Apache, который регистрирует и отображает фактический IP-адрес посетителя, а не адрес CloudFlare:

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

Было бы трудно конвертировать 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']);

Узнайте больше здесь

HTTP_CF_CONNECTING_IP работает только в том случае, если вы используете cloudflare, возможно, вы перенесли свой сайт или удалили cloudflare, и вы забудете значение, поэтому используйте этот код.

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

Когда вы используете CloudFlare, все ваши запросы между вашим сервером и пользователями направляются через серверы CloudFlare.

В этом случае есть два способа получить реальный IP-адрес пользователя:

  1. Через дополнительные заголовки сервера, добавленные CloudFlare Servers
  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 на ваш сервер

У Cloudflare есть возможность использовать адрес «Псевдо IPv4» в заголовках на странице «Управление сетью» для домена. У вас есть возможность добавить или перезаписать заголовки, отправляемые на ваш сервер.

Из документации:

Что такое псевдоIPv4?

В качестве временной меры для ускорения внедрения IPv6 Cloudflare предлагает псевдо-IPv4, который поддерживает адреса IPv6 в устаревших приложениях, ожидающих адресов IPv4. Цель состоит в том, чтобы предоставить почти уникальный IPv4-адрес для каждого IPv6-адреса, используя адресное пространство IPv4 класса E, которое обозначено как экспериментальное и обычно не пропускает трафик. Чтобы узнать больше , смотрите здесь.

Опции

  • Добавить заголовок: Добавить дополнительные Cf-Pseudo-IPv4только заголовок
  • Перезаписать заголовки: перезаписать существующие Cf-Connecting-IPа также X-Forwarded-Forзаголовки с псевдоадресом IPv4.

Примечание. Мы рекомендуем оставить для этого параметра значение «Выкл.», если у вас нет особой необходимости.

Вы можете узнать больше об этой функции из этой статьи от Cloudflare, где немного подробнее рассказывается о том, как они пытаются разместить 128-битное адресное пространство IPv6 в 32-битном пространстве IPv4.

Если вы хотите узнать IPv6-адрес вместе с псевдо-IPv4, Cloudflare добавляет Cf-Connecting-IPv6заголовок, когда псевдо-IPv4 включен. Это можно использовать для измерения того, какая часть вашего трафика исходит от устройств, которые находятся в сетях IPv6, что может быть полезно, если вам нужно надежное число для демонстрации управления до того, как будут сделаны инвестиции в обновление систем, которые все еще привязаны к ограничениям IPv4.

Лучше проверить диапазоны IP-адресов Cloudflare онлайн (потому что они могут измениться в любое время), а затем проверить, принадлежит ли он Cloudflare или нет.

Cloudflare IP-текст

Если источником является Cloudflare, вы можете использовать $_SERVER['HTTP_CF_CONNECTING_IP']чтобы получить IP-адрес запроса вашего клиента, но использовать его для всех запросов небезопасно, потому что он может быть отправлен любым пользователем в заголовке запроса, чтобы обмануть вас.

Вы можете использовать следующий код, чтобы получить реальный IP-адрес вашего клиентского запроса:

      function _getUserRealIP() {
    $ipaddress = '';
    if(isset($_SERVER['REMOTE_ADDR']))
        $ipaddress = $_SERVER['REMOTE_ADDR'];
    else if (isset($_SERVER['HTTP_CLIENT_IP']))
        $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
    else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
    else if(isset($_SERVER['HTTP_X_FORWARDED']))
        $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
    else if(isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
        $ipaddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
    else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
        $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
    else if(isset($_SERVER['HTTP_FORWARDED']))
        $ipaddress = $_SERVER['HTTP_FORWARDED'];
    else
        $ipaddress = 'UNKNOWN';
    return $ipaddress;
}

function _readCloudflareIps()
{
    $file = file("https://www.cloudflare.com/ips-v4",FILE_IGNORE_NEW_LINES);
    return $file;
}

function _checkIpInRange($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 _checkIsCloudflare($ip) {
    $cf_ips = _readCloudflareIps();
    $is_cf_ip = false;
    foreach ($cf_ips as $cf_ip) {
        if (_checkIpInRange($ip, $cf_ip)) {
            $is_cf_ip = true;
            break;
        }
    }
    return $is_cf_ip;
}

function getRealIp()
{
    $httpIp = _getUserRealIP();
    $check = _checkIsCloudflare($httpIp);
    if ($check) {
        return $_SERVER['HTTP_CF_CONNECTING_IP'];
    }else{
        return $httpIp;
    }
}

После импорта этих функций в ваш код вам просто нужно позвонить getRealIp()функция как:

      $userIp = getRealIp();
echo $userIp();

В Laravel добавьте следующую строку в AppServiceProvider:

...
use Symfony\Component\HttpFoundation\Request;


...
public function boot()
{
    Request::setTrustedProxies(['REMOTE_ADDR'], Request::HEADER_X_FORWARDED_FOR);
}

Теперь вы можете получить реальный IP клиента, используя request()->ip().

Подробнее читайте здесь.

Для пользователей magento 1.x (я еще не пробовал magento 2.0), проверьте https://tall-paul.co.uk/2012/03/13/magento-show-remote-ip-in-cloudflare-the-right-way/ который должен изменить app/etc/local.xml и добавить: HTTP_CF_CONNECTING_IP

другой способ получить его в Laravel — просто прочитать заголовок HTTP_CF_CONNECTING_IP.

      $request->server('HTTP_CF_CONNECTING_IP')

вы можете прочитать больше об этом здесь:Как получить реальный IP-адрес клиента за Cloudflare в Laravel/PHP

      function getClientIP() {
  $ipaddress = 'UNKNOWN';
  $SRC = array('HTTP_CF_CONNECTING_IP','HTTP_CLIENT_IP','HTTP_X_FORWARDED_FOR','HTTP_X_FORWARDED','HTTP_FORWARDED_FOR','HTTP_FORWARDED','REMOTE_ADDR');
  foreach($SRC as $src) {
    if (isset($_SERVER[$src])) {
        $ipaddress = $_SERVER[$src];
        continue;
    }
  }
  return $ipaddress;
}
Другие вопросы по тегам