2009-02-09 13 views
54

Entiendo que es una práctica estándar mirar estas dos variables. Por supuesto, pueden ser falsificados fácilmente. Tengo curiosidad de la frecuencia con la que puede esperar que estos valores (especialmente el HTTP_X_FORWARDED_FOR) contengan información genuina y no solo que se codifiquen o que se eliminen sus valores.Obteniendo la dirección IP del cliente: REMOTE_ADDR, HTTP_X_FORWARDED_FOR, ¿qué más podría ser útil?

¿Alguien con experiencia o estadísticas sobre esta materia?

¿Hay algo más que pueda ser útil para la tarea de obtener la dirección IP del cliente?

+0

Tenga en cuenta que tanto la pregunta como las respuestas usan el prefijo HTTP_, que es un detalle de implementación particular de ASP.NET v1.0-v4.x, cuando los encabezados de solicitud HTTP se agregan a la colección ServerVariables. Otro ejemplo es REMOTE_ADDR, que tiene su propia API en ASP.NET Core. https://stackoverflow.com/questions/28664686/how-do-i-get-client-ip-address-in-asp-net-core – yzorg

Respuesta

26

Depende de la naturaleza de su sitio.

Funciono en un poco de software donde el seguimiento de IP es importante, y dentro de un campo consumido por sitios de partidas supongo que un 20% - 40% de las solicitudes son direcciones IP detectables o encabezados borrados, dependiendo a la hora del día y de dónde vinieron. Para un sitio que obtiene tráfico orgánico (es decir, no a través de socios), esperaría una proporción mucho más alta de buenas IP.

Como dijo Kosi, tenga cuidado con lo que hace con esto: los IP de ninguna manera son una forma confiable de identificar visitantes únicos.

7

No hay una respuesta real a su pregunta pero:
En general, confiar en la dirección IP del cliente no es una buena práctica en mi opinión, ya que no se puede identificar a los clientes de una manera única.

Problemas en la carretera son que hay bastantes escenarios donde la IP en realidad no se alinean a un cliente:

  • Proxy/Webfilter (mangle casi todo)
  • red Anonymizer (sin oportunidad aquí tampoco)
  • NAT (una IP interna no es muy útil para usted)
  • ...

no puedo ofrecer una y las estadísticas sobre cuántas direcciones IP son en promedio confiables pero lo que puedo decirle es que es casi imposible decir si una dirección IP dada es la dirección real del cliente.

+0

¿Cuál es la 'mejor práctica' para * identificar clientes de una manera única *? *** Lista de comprobación ***: _No utilizar clientes dirección IP_ – Kiquenet

2

IP + "User Agent" podría ser una mejor opción para un visitante único.

+0

nah, los agentes de usuario no son muy diversos y son ampliamente falsificados – annakata

+5

ampliamente falsificados, pero en general no cambian de solicitud a solicitud - http: //panopticlick.eff .org/ – wprl

55

Además de REMOTE_ADDR y HTTP_X_FORWARDED_FOR hay algunas otras cabeceras que se pueden definir como:

  • HTTP_CLIENT_IP
  • HTTP_X_FORWARDED_FOR puede haber lista delimitada por comas de IPs
  • HTTP_X_FORWARDED
  • HTTP_X_CLUSTER_CLIENT_IP
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED

He encontrado el código siguiente en el sitio útil:
http://www.grantburton.com/?p=97

+0

¿Es esta lista de alguna manera completa, lo que significa que cubre más del 90% de todos los proxies? – basZero

+4

No creo que esos encabezados deberían tener el prefijo HTTP_ ... un poco de búsqueda apareció http://stackoverflow.com/questions/3834083/http-headers-what-is-the-difference-between-x-forwarded -for-x-forward-for-a – lmsurprenant

+0

También hay un Referer ahora, según [RFC 7239] (https://tools.ietf.org/html/rfc7239) – Kevin

10

he portado código PHP de subvención Burton a un método estático ASP.Net exigible en contra de la HttpRequestBase. Omitirá de manera opcional a través de cualquier rango de IP privado.

public static class ClientIP 
{ 
    // based on http://www.grantburton.com/2008/11/30/fix-for-incorrect-ip-addresses-in-wordpress-comments/ 
    public static string ClientIPFromRequest(this HttpRequestBase request, bool skipPrivate) 
    { 
     foreach (var item in s_HeaderItems) 
     { 
      var ipString = request.Headers[item.Key]; 

     if (String.IsNullOrEmpty(ipString)) 
      continue; 

     if (item.Split) 
     { 
      foreach (var ip in ipString.Split(',')) 
       if (ValidIP(ip, skipPrivate)) 
        return ip; 
     } 
     else 
     { 
      if (ValidIP(ipString, skipPrivate)) 
       return ipString; 
     } 
    } 

    return request.UserHostAddress; 
} 

private static bool ValidIP(string ip, bool skipPrivate) 
{ 
    IPAddress ipAddr; 

    ip = ip == null ? String.Empty : ip.Trim(); 

    if (0 == ip.Length 
     || false == IPAddress.TryParse(ip, out ipAddr) 
     || (ipAddr.AddressFamily != AddressFamily.InterNetwork 
      && ipAddr.AddressFamily != AddressFamily.InterNetworkV6)) 
     return false; 

    if (skipPrivate && ipAddr.AddressFamily == AddressFamily.InterNetwork) 
    { 
     var addr = IpRange.AddrToUInt64(ipAddr); 
     foreach (var range in s_PrivateRanges) 
     { 
      if (range.Encompasses(addr)) 
       return false; 
     } 
    } 

    return true; 
} 

/// <summary> 
/// Provides a simple class that understands how to parse and 
/// compare IP addresses (IPV4) ranges. 
/// </summary> 
private sealed class IpRange 
{ 
    private readonly UInt64 _start; 
    private readonly UInt64 _end; 

    public IpRange(string startStr, string endStr) 
    { 
     _start = ParseToUInt64(startStr); 
     _end = ParseToUInt64(endStr); 
    } 

    public static UInt64 AddrToUInt64(IPAddress ip) 
    { 
     var ipBytes = ip.GetAddressBytes(); 
     UInt64 value = 0; 

     foreach (var abyte in ipBytes) 
     { 
      value <<= 8; // shift 
      value += abyte; 
     } 

     return value; 
    } 

    public static UInt64 ParseToUInt64(string ipStr) 
    { 
     var ip = IPAddress.Parse(ipStr); 
     return AddrToUInt64(ip); 
    } 

    public bool Encompasses(UInt64 addrValue) 
    { 
     return _start <= addrValue && addrValue <= _end; 
    } 

    public bool Encompasses(IPAddress addr) 
    { 
     var value = AddrToUInt64(addr); 
     return Encompasses(value); 
    } 
}; 

private static readonly IpRange[] s_PrivateRanges = 
    new IpRange[] { 
      new IpRange("0.0.0.0","2.255.255.255"), 
      new IpRange("10.0.0.0","10.255.255.255"), 
      new IpRange("127.0.0.0","127.255.255.255"), 
      new IpRange("169.254.0.0","169.254.255.255"), 
      new IpRange("172.16.0.0","172.31.255.255"), 
      new IpRange("192.0.2.0","192.0.2.255"), 
      new IpRange("192.168.0.0","192.168.255.255"), 
      new IpRange("255.255.255.0","255.255.255.255") 
    }; 


/// <summary> 
/// Describes a header item (key) and if it is expected to be 
/// a comma-delimited string 
/// </summary> 
private sealed class HeaderItem 
{ 
    public readonly string Key; 
    public readonly bool Split; 

    public HeaderItem(string key, bool split) 
    { 
     Key = key; 
     Split = split; 
    } 
} 

// order is in trust/use order top to bottom 
private static readonly HeaderItem[] s_HeaderItems = 
    new HeaderItem[] { 
      new HeaderItem("HTTP_CLIENT_IP",false), 
      new HeaderItem("HTTP_X_FORWARDED_FOR",true), 
      new HeaderItem("HTTP_X_FORWARDED",false), 
      new HeaderItem("HTTP_X_CLUSTER_CLIENT_IP",false), 
      new HeaderItem("HTTP_FORWARDED_FOR",false), 
      new HeaderItem("HTTP_FORWARDED",false), 
      new HeaderItem("HTTP_VIA",false), 
      new HeaderItem("REMOTE_ADDR",false) 
    }; 
} 
+2

Gracias por el código. Sin embargo, hay un par de problemas con eso.Primero, hay un 'return false;' extra en 'ValidIP'. En segundo lugar, la clase IpRange realmente no maneja IPV6 ya que las direcciones IPV6 son de 128 bits. Quizás podría usarse 'System.Numerics.BigInteger' de .NET 4, pero también es posible que los rangos privados sean menos interesantes con IPV6 de todos modos (?). –

+1

Ah, y otro problema: en lugar de comprobar encabezados de request.Headers, creo que desea request.ServerVariables. Este último tiene claves como 'HTTP_X_FORWARDED_FOR' mientras que el primero sería' X-Forwarded-For'. –

+0

Sería genial si esto también es compatible [RFC 7239] (https://tools.ietf.org/html/rfc7239): D – Kevin

1

Si estás detrás de un proxy, se debe usar X-Forwarded-For: http://en.wikipedia.org/wiki/X-Forwarded-For

Es un IETF draft standard con un amplio apoyo:

El X-reenviado-Para el campo es apoyado por la mayoría servidores proxy, incluyendo Squid, Apache mod_proxy, Pound, HAProxy, Varnish cache, IronPort Web Security Appliance, AVANU WebMux, ArrayNetworks, Radware's AppDirector y Alteon ADC, ADC-VX, a nd ADC-VA, F5 Big-IP, Blue Coat ProxySG, Cisco Cache Engine, McAfee Web Gateway, Phion Airlock, Finjan's Vital Security, NetApp NetCache, jetNEXUS, Crescendo Networks 'Maestro, Web Adjuster y Websense Web Security Gateway.

Si no, aquí hay un par de otras cabeceras comunes que he visto:

Cuestiones relacionadas