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

82

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

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

108.162.212. * - 108.162.239. *

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

tfont
источник

Ответы:

241

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

$_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-адресу сервера.

острый12345
источник
16
+1 за замену REMOTE_ADDR на реальный IP, поэтому никаких других изменений в коде не требуется.
aalaap
11
Если безопасность имеет значение, следует проверить, исходит ли запрос из диапазона IP-адресов Cloudflare ( cloudflare.com/ips ). Как например в этой Joomla! Плагин: github.com/piccaso/joomla-cf/blob/master/cf/cf.php
Флориан Фида,
Этот код также указан на сайте 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! https://www.cloudflare.com/resources-downloads#mod_cloudflare (ответ: olimortimer )

Если у вас нет доступа к среде выполнения apache, вы можете использовать приведенный ниже сценарий, это позволит вам проверить, было ли соединение через cloudflare, и получить IP-адрес пользователя.

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

IP-адреса Cloudflare хранятся в открытом доступе, поэтому вы можете просмотреть их здесь, а затем проверить, не принадлежит ли IP-адрес Cloudflare (это позволит нам получить реальный 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 "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 07
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был
получен
@sjagr, что касается ваших правок, они неверны - CloudFlare на самом деле является Cloudflare, как я изначально
писал
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.
Sainan
Да, конечно. Это хорошее решение само по себе, но перед использованием HTTP_CF_CONNECTING_IP все равно следует проводить проверки, как в ответе Каллума
rafark
@rafark Я также согласен, но это ужасно много кода PHP, который уже присутствует в другой форме в вашей конфигурации Apache (я надеюсь), и этот код больше предназначен для облегчения отладки, и если у злоумышленника есть доступ к вашей среде отладки, я думаю у вас есть более важные проблемы.
Sainan
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'];
}
RootTools
источник
1

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

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


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

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

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

Халил Лалех
источник
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 на ваш сервер

Ашутош Кумар
источник