CloudFlare i logowanie adresów IP gości za pośrednictwem PHP

82

Próbuję śledzić i rejestrować użytkowników / odwiedzających, którzy uzyskują dostęp do mojej witryny za pomocą PHP, $_SERVER['REMOTE_ADDR']aby to zrobić. Typowa metoda śledzenia adresów IP w PHP.

Jednak używam CloudFlare do buforowania i otrzymuję ich adresy IP jako CloudFlare:

108.162.212. * - 108.162.239. *

Jaka byłaby poprawna metoda pobierania rzeczywistych adresów IP użytkowników / odwiedzających, podczas gdy nadal korzystasz z CloudFlare?

tfont
źródło

Odpowiedzi:

241

Dodatkowe zmienne serwera, które są dostępne dla flary chmury to:

$_SERVER["HTTP_CF_CONNECTING_IP"] prawdziwy adres IP gościa, właśnie tego chcesz

$_SERVER["HTTP_CF_IPCOUNTRY"] kraj odwiedzającego

$_SERVER["HTTP_CF_RAY"]

$_SERVER["HTTP_CF_VISITOR"] Dzięki temu dowiesz się, czy jest to http czy https

możesz tego użyć w ten sposób:

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

Jeśli to zrobisz, a ważność odwiedzającego adresu IP jest ważna, może być konieczne sprawdzenie, czy $_SERVER["REMOTE_ADDR"]zawiera rzeczywisty prawidłowy adres IP Cloudflare, ponieważ każdy może sfałszować nagłówek, jeśli był w stanie połączyć się bezpośrednio z adresem IP serwera.

ostry12345
źródło
16
+1 za zastąpienie REMOTE_ADDR prawdziwym adresem IP, więc żadne inne modyfikacje w kodzie nie są wymagane.
aalaap
11
Jeśli bezpieczeństwo ma znaczenie, należy sprawdzić, czy żądanie pochodzi z zakresu adresów IP Cloudflare ( cloudflare.com/ips ). Na przykład w tym Joomla! Wtyczka: github.com/piccaso/joomla-cf/blob/master/cf/cf.php
Florian Fida
Cloudflare również ma ten kod na swojej stronie. support.cloudflare.com/hc/en-us/articles/…
C0nw0nk
Najlepsza odpowiedź, ale także pochwały za uwzględnienie HTTP_CF_IPCOUNTRY, wcześniej nie spotkałem się z tym.
David Bell
http_cf_connecting_ip czasami podaje takie rzeczy jak: 2a01: 6500: a043: 33a6: b36a: 7259: 4de5: 2500 jakiś pomysł, dlaczego?
michael
15

Aktualizacja : CloudFlare wydał moduł mod_cloudflaredla Apache, moduł będzie logował i wyświetlał rzeczywiste adresy IP odwiedzających, a nie te, do których uzyskuje dostęp cloudflare! https://www.cloudflare.com/resources-downloads#mod_cloudflare (odpowiedź od: olimortimer )

Jeśli nie masz dostępu do środowiska uruchomieniowego Apache, możesz użyć poniższego skryptu, który pozwoli ci sprawdzić, czy połączenie było przez Cloudflare i uzyskać IP użytkowników.

Przepisuję odpowiedź, której użyłem do innego pytania „ CloudFlare DNS / direct IP identifier

Adresy IP Cloudflare są przechowywane publicznie, więc możesz je wyświetlić tutaj, a następnie sprawdzić, czy adres IP pochodzi z Cloudflare (pozwoli nam to uzyskać prawdziwy adres IP z nagłówka http HTTP_CF_CONNECTING_IP).

Jeśli używasz tego do wyłączania wszystkich połączeń innych niż cf lub odwrotnie, polecam mieć jeden plik skryptu php, który jest wywoływany przed każdym innym skryptem, takim jak common.php lub pagestart.php itp.

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'];
    }
}

Korzystanie ze skryptu jest dość proste:

$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'];

Ten skrypt pokaże ci prawdziwy adres IP i czy żądanie jest CF, czy nie!

Callum
źródło
To jest poprawna odpowiedź, jednak pamiętaj, że musisz regularnie aktualizować adresy IP. Obecne w powyższym kodzie są już nieprawidłowe i dlatego kod się nie powiedzie. Możesz pobrać najnowsze adresy IP tutaj: cloudflare.com/ips Najlepiej byłoby przechowywać je w pliku, aby wystarczyło zaktualizować plik zewnętrzny lub nawet lepiej, okresowo pobierać je stąd: cloudflare.com/ips-v4
rafark
11

Ponieważ zadano to pytanie i udzielono odpowiedzi, CloudFlare wydał mod_cloudflaredla Apache, który rejestruje i wyświetla rzeczywisty adres IP odwiedzającego zamiast adresu CloudFlare:

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

olimortimer
źródło
2019 - Już nie obsługują mod_cloudflare, ale można z niego korzystać. Jest coś nowego mod_remoteip.
Źródła
@sinaza chyba najlepiej jest stworzyć nową odpowiedź, ponieważ moja odpowiedź mod_cloudflarebyła sprzed 4 lat
olimortimer
@sjagr w odniesieniu do twoich zmian, są one niepoprawne - CloudFlare to w rzeczywistości Cloudflare, jak pierwotnie
napisałem
10

Cloudflare wysyła dodatkowe nagłówki żądań do twojego serwera, w tym te, CF-Connecting-IPktóre możemy przechowywać $user_ip, jeśli są zdefiniowane, za pomocą tego prostego jednowierszowego:

$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"])?$_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);
Sainan
źródło
Problem polega na tym, że to tylko prosty nagłówek, więc każdy może ustawić go na dowolny adres IP, co jest ogromną luką w zabezpieczeniach.
rafark
@rafark Nie, jeśli twój serwer jest poprawnie skonfigurowany i za Cloudflare.
Sainan
Tak oczywiście. Jest to dobre rozwiązanie samo w sobie, ale nadal należy sprawdzić przed użyciem HTTP_CF_CONNECTING_IP, jak w odpowiedzi
Calluma
@rafark Też się zgadzam, ale jest to bardzo dużo kodu PHP, który jest już obecny w innej formie w twojej konfiguracji Apache (mam nadzieję) i ten kod jest bardziej umożliwiający łatwe debugowanie i jeśli atakujący ma dostęp do twojego środowiska debugowania, myślę masz ważniejsze problemy do rozwiązania.
Sainan
2

Trudno byłoby przekonwertować HTTP_CF_CONNECTING_IP na REMOTE_ADDR. Możesz więc użyć do tego automatycznego poprzedzania apache (.htaccess). Dzięki temu nie musisz zastanawiać się, czy $_SERVER['REMOTE_ADDR']we wszystkich skryptach PHP ma poprawną wartość.

.htaccess code

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

kod php (plik.php)

<?php

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

Dowiedz się więcej tutaj

Supun Kavinda
źródło
1

HTTP_CF_CONNECTING_IP działa tylko wtedy, gdy używasz cloudflare, być może przenosisz swoją witrynę lub usuniesz cloudflare, zapomnisz wartości, więc użyj tego kodu.

$ip=$_SERVER["HTTP_CF_CONNECTING_IP"];
if (!isset($ip)) {
  $ip = $_SERVER['REMOTE_ADDR'];
}
RootTools
źródło
1

W Laravel dodaj następujący wiersz do AppServiceProvider:

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


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

Teraz możesz uzyskać prawdziwy adres IP klienta za pomocą request()->ip().

Przeczytaj więcej tutaj .

Khalil Laleh
źródło
0

Kiedy używasz CloudFlare, wszystkie twoje żądania między twoim serwerem a użytkownikami są kierowane przez serwery CloudFlare.

W takim przypadku istnieją dwie metody uzyskania prawdziwego adresu IP użytkownika:

  1. Poprzez dodatkowe nagłówki serwera dodane przez serwery CloudFlare
  2. Dodanie modułu CloudFlare Apache / NGINX na serwerze.

Metoda 1: Uzyskaj adres IP przez dodatkowe nagłówki serwera

Aby uzyskać adres IP użytkownika, możesz użyć następującego kodu:

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

Jak to działa?

CloudFlare dodaje kilka dodatkowych zmiennych serwera w żądaniu w następujący sposób:

$_SERVER["HTTP_CF_CONNECTING_IP"] - Rzeczywisty adres IP użytkownika

$_SERVER["HTTP_CF_IPCOUNTRY"] - Kraj użytkownika ISO2

$_SERVER["HTTP_CF_RAY"] Specjalny ciąg znaków do celów logowania

W powyższym kodzie sprawdzamy, czy $_SERVER["HTTP_CF_CONNECTING_IP"]jest ustawiony, czy nie. Jeśli tam jest, uznamy, że jako adres IP użytkownika w innym przypadku użyjemy domyślnego kodu jako$_SERVER['REMOTE_ADDR']

Metoda 2: Instalacja modułu Cloudflare na serwerze

Ashutosh Kumar
źródło