获取客户端IP地址:REMOTE_ADDR,HTTP_X_FORWARDED_FOR,还有什么用处?

获取客户端IP地址:REMOTE_ADDR,HTTP_X_FORWARDED_FOR,还有什么用处?

问题描述:

我明白这是一个标准的做法,看看这两个变量。当然,他们很容易被欺骗。我很好奇你多久可以期望这些值(特别是HTTP_X_FORWARDED_FOR)能够包含真实信息,而不仅仅是被混淆或被剥夺了价值?获取客户端IP地址:REMOTE_ADDR,HTTP_X_FORWARDED_FOR,还有什么用处?

任何人都有这方面的经验或统计资料?

对于获取客户端IP地址的任务还有什么可以使用吗?

+0

请注意,当HTTP请求标头添加到ServerVariables集合时,问题和答案都使用HTTP_前缀,该前缀是ASP.NET v1.0-v4.x的特定实现细节。另一个例子是REMOTE_ADDR,在ASP.NET Core中有它自己的API。 https://*.com/questions/28664686/how-do-i-get-client-ip-address-in-asp-net-core – yzorg 2017-12-11 14:24:10

这取决于你的网站的性质。

我碰巧在一些IP跟踪非常重要的软件上工作,并且在参与者站点使用的字段中,我猜想有20%-40%的请求要么是可检测到的IP地址,要么是标题空白,取决于在一天的时间和他们来自哪里。对于获得有机流量的网站(即不通过合作伙伴),我希望有更好的IP比例。

正如Kosi所说,要小心你在做什么 - IPs绝不是确定独特访客的可靠方法。

对您的问题没有真正的答案,但:
通常依靠客户端IP地址在我看来不是一个好的做法,因为它不能用于以独特的方式识别客户端。在路上

的问题是,有相当多的场景中的IP并没有真正对齐到客户端:

  • 代理/网页过滤(轧液几乎所有)
  • 匿名者网络(这里没有机会要么)
  • NAT(内部IP是不是对你非常有用)
  • ...

我不能提供一个y关于多少个IP地址的平均值的统计可靠,但我可以告诉你几乎不可能分辨给定的IP地址是否是真正的客户端地址。

+0

哪些是“最佳实践”*以独特的方式识别客户*? ***清单***:_Not use clients IP address_ – Kiquenet 2016-11-15 11:51:09

IP +“用户代理”对于独特访客可能更好。

+0

nah,用户代理不是很多元化,并且被广泛欺骗,无论如何 – annakata 2009-02-10 20:20:51

+5

被广泛欺骗,但通常它们不会从请求更改为请求 - http://panopticlick.eff .org/ – wprl 2010-02-22 22:15:17

除了REMOTE_ADDRHTTP_X_FORWARDED_FOR有可以设置诸如其他一些标题:

  • HTTP_CLIENT_IP
  • HTTP_X_FORWARDED_FOR可以用逗号分隔的IP地址列表
  • HTTP_X_FORWARDED
  • HTTP_X_CLUSTER_CLIENT_IP
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED

我发现下面的网站有用的代码:
http://www.grantburton.com/?p=97

+0

这个列表是否完整,意思是覆盖了所有代理的90%以上? – basZero 2014-01-10 17:13:41

我已经转移了格兰特·波顿的PHP代码到一个ASP.Net静态方法调用针对HttpRequestBase。它可以选择跳过任何专用IP范围。

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) 
    }; 
} 

如果你是一个代理之后,你应该使用X-Forwarded-Forhttp://en.wikipedia.org/wiki/X-Forwarded-For

它与广泛支持的IETF draft standard

的X转发,对于现场被大多数支持代理服务器, 包括Squid,Apache mod_proxy,Pound,HAProxy,Varnish缓存, Radware的AppDirector和Alteon ADC,ADC-VX,a网络的Maestro,网页调整器和Websense网络安全网关。该公司的网络服务器,网络调节器和Websense网络安全网关。

如果不是这样,这里有一些其他常见的头我见过: