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:
Было бы трудно конвертировать 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-адрес пользователя:
- Через дополнительные заголовки сервера, добавленные CloudFlare Servers
- Добавление модуля 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, вы можете использовать
$_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;
}