CloudFlare y registro de direcciones IP de visitantes a través de PHP

82

Estoy tratando de rastrear y registrar a los usuarios / visitantes que acceden a mi sitio web usando PHP $_SERVER['REMOTE_ADDR']para hacerlo. Un método típico para el seguimiento de direcciones IP en PHP.

Sin embargo, estoy usando CloudFlare para almacenar en caché y recibir sus direcciones IP como las de CloudFlare:

108.162.212. * - 108.162.239. *

¿Cuál sería un método correcto para recuperar la dirección IP de los usuarios / visitantes reales sin dejar de usar CloudFlare?

tfont
fuente

Respuestas:

239

Las variables de servidor adicionales que están disponibles para Cloud Flare son:

$_SERVER["HTTP_CF_CONNECTING_IP"] dirección IP de visitante real, esto es lo que quieres

$_SERVER["HTTP_CF_IPCOUNTRY"] país del visitante

$_SERVER["HTTP_CF_RAY"]

$_SERVER["HTTP_CF_VISITOR"] esto puede ayudarlo a saber si es http o https

puedes usarlo así:

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

Si hace esto, y la validez de la dirección IP de visita es importante, es posible que deba verificar que $_SERVER["REMOTE_ADDR"]contiene una dirección IP de nube real válida, ya que cualquiera puede falsificar el encabezado si pudo conectarse directamente a la IP del servidor.

agudo12345
fuente
15
+1 para reemplazar REMOTE_ADDR con la IP real, por lo que no se requieren otras modificaciones en el código.
aalaap
11
Si la seguridad es importante, se debe verificar si la solicitud proviene de un rango de IP de Cloudflare ( cloudflare.com/ips ). Como, por ejemplo, en este Joomla! Complemento
Florian Fida
Cloudflare también tiene este código en su sitio. support.cloudflare.com/hc/en-us/articles/…
C0nw0nk
La mejor respuesta, pero también felicitaciones por incluir HTTP_CF_IPCOUNTRY, no me había encontrado con esa antes.
David Bell
http_cf_connecting_ip a veces da cosas como: 2a01: 6500: a043: 33a6: b36a: 7259: 4de5: 2500 alguna idea de por qué?
Michael
15

Actualización : CloudFlare ha lanzado un módulo mod_cloudflarepara apache, el módulo registrará y mostrará las direcciones IP reales de los visitantes en lugar de las a las que accede cloudflare. https://www.cloudflare.com/resources-downloads#mod_cloudflare (Respuesta de: olimortimer )

Si no tiene acceso al tiempo de ejecución de apache, puede usar el siguiente script, esto le permitirá verificar si la conexión fue a través de cloudflare y obtener la ip de los usuarios.

Estoy reescribiendo mi respuesta que usé para otra pregunta " Identificador de IP directo / DNS de CloudFlare "

Las ips de Cloudflare se almacenan en público para que pueda verlas aquí y luego verificar si la ip es de cloudflare (esto nos permitirá obtener la ip real del encabezado http HTTP_CF_CONNECTING_IP).

Si está usando esto para deshabilitar todas las conexiones que no sean de cf o viceversa, le recomiendo que tenga un único archivo de script php que se llame antes que cualquier otro script, como common.php o pagestart.php, etc.

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

Usar el script es bastante simple:

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

Este script le mostrará la dirección IP real y si la solicitud es CF o no.

Callum
fuente
Esta es la respuesta correcta, sin embargo, tenga en cuenta que debe seguir actualizando las IP con regularidad. Los actuales en el código anterior ya no son válidos y, por lo tanto, el código fallará. Puede obtener las últimas IP aquí: cloudflare.com/ips Idealmente, debería almacenarlas en un archivo para que solo tenga que actualizar el archivo externo o, mejor aún, obtenerlas
rafark
11

Desde que se hizo y respondió esta pregunta, CloudFlare ha lanzado mod_cloudflarepara Apache, que registra y muestra la dirección IP real del visitante en lugar de la dirección de CloudFlare:

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

olimortimer
fuente
2019: ya no son compatibles mod_cloudflare, pero se pueden usar. Hay algo nuevo llamado mod_remoteip. Referencia: support.cloudflare.com/hc/en-us/articles/…
sinaza
@sinaza probablemente sea mejor para crear una nueva respuesta, ya que mi respuesta mod_cloudflarefue de hace 4 años
olimortimer
@sjagr en lo que respecta a sus ediciones, son incorrectas: CloudFlare es en realidad Cloudflare, como publiqué originalmente
olimortimer
10

Cloudflare envía algunos encabezados de solicitud adicionales a su servidor, incluidos los CF-Connecting-IPque podemos almacenar $user_ip, si se definen, utilizando este sencillo resumen:

$user_ip = (isset($_SERVER["HTTP_CF_CONNECTING_IP"])?$_SERVER["HTTP_CF_CONNECTING_IP"]:$_SERVER['REMOTE_ADDR']);
Sainan
fuente
El problema con esto es que es solo un encabezado simple, por lo que cualquiera puede configurarlo en la IP que desee, lo cual es una gran vulnerabilidad de seguridad.
Rafark
@rafark No si su servidor está configurado correctamente y detrás de Cloudflare.
Sainan
Sí, por supuesto. Esta es una buena solución per se, pero aún se deben realizar verificaciones antes de usar HTTP_CF_CONNECTING_IP, como en la respuesta de Callum
rafark
@rafark También estoy de acuerdo, pero esa es una gran cantidad de código PHP que ya está presente en otra forma en su configuración de Apache (espero) y este código es más para permitir una depuración fácil y si un atacante tiene acceso a su entorno de depuración, creo tiene problemas más importantes que tratar.
Sainan
2

Sería difícil convertir HTTP_CF_CONNECTING_IP a REMOTE_ADDR. Entonces puede usar apache (.htaccess) auto anteponiendo para hacer eso. Para que no tenga que pensar si $_SERVER['REMOTE_ADDR']tiene el valor correcto en todos los scripts PHP.

.htaccess código

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

código php (file.php)

<?php

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

Más información aquí

Supun Kavinda
fuente
1

HTTP_CF_CONNECTING_IP solo funciona si está usando cloudflare, tal vez transfiera su sitio o elimine cloudflare, olvidará el valor, así que use este código.

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

Cuando usa CloudFlare, todas sus solicitudes entre su servidor y los usuarios se enrutan a través de los servidores de CloudFlare.

En este caso, existen dos métodos para obtener la dirección IP real del usuario:

  1. A través de encabezados de servidor adicionales agregados por servidores CloudFlare
  2. Agregar un módulo CloudFlare Apache / NGINX en su servidor.

Método 1: obtener IP a través de encabezados de servidor adicionales

Puede utilizar el siguiente código para obtener la dirección IP del usuario:

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

¿Cómo está funcionando?

CloudFlare agrega algunas variables de servidor adicionales en la solicitud de la siguiente manera:

$_SERVER["HTTP_CF_CONNECTING_IP"] - Dirección IP real del usuario

$_SERVER["HTTP_CF_IPCOUNTRY"] - País ISO2 del usuario

$_SERVER["HTTP_CF_RAY"] Una cadena especial para fines de registro

En el código anterior, estamos verificando si $_SERVER["HTTP_CF_CONNECTING_IP"]está configurado o no. Si está allí, consideraremos que como dirección IP del usuario, de lo contrario, usaremos el código predeterminado como$_SERVER['REMOTE_ADDR']

Método 2: Instalación del módulo Cloudflare en su servidor

Ashutosh Kumar
fuente