2009-02-09 62 views
54

我明白這是一個標準的做法,看看這兩個變量。當然,他們很容易被欺騙。我很好奇你多久可以期望這些值(特別是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://stackoverflow.com/questions/28664686/how-do-i-get-client-ip-address-in-asp-net-core – yzorg 2017-12-11 14:24:10

回答

26

這取決於你的網站的性質。

我碰巧在一些IP跟蹤非常重要的軟件上工作,並且在參與者站點使用的字段中,我猜想有20%-40%的請求要麼是可檢測到的IP地址,要麼是標題空白,取決於在一天的時間和他們來自哪裏。對於獲得有機流量的網站(即不通過合作伙伴),我希望有更好的IP比例。

正如Kosi所說,要小心你在做什麼 - IPs絕不是確定獨特訪客的可靠方法。

7

對您的問題沒有真正的答案,但:
通常依靠客戶端IP地址在我看來不是一個好的做法,因爲它不能用於以獨特的方式識別客戶端。在路上

的問題是,有相當多的場景中的IP並沒有真正對齊到客戶端:

  • 代理/網頁過濾(軋液幾乎所有)
  • 匿名者網絡(這裏沒有機會要麼)
  • NAT(內部IP是不是對你非常有用)
  • ...

我不能提供一個y關於多少個IP地址的平均值的統計可靠,但我可以告訴你幾乎不可能分辨給定的IP地址是否是真正的客戶端地址。

+0

哪些是「最佳實踐」*以獨特的方式識別客戶*? ***清單***:_Not use clients IP address_ – Kiquenet 2016-11-15 11:51:09

2

IP +「用戶代理」對於獨特訪客可能更好。

+0

nah,用戶代理不是很多元化,並且被廣泛欺騙,無論如何 – annakata 2009-02-10 20:20:51

+5

被廣泛欺騙,但通常它們不會從請求更改爲請求 - http://panopticlick.eff .org/ – wprl 2010-02-22 22:15:17

55

除了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

10

我已經轉移了格蘭特·波頓的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) 
    }; 
} 
1

如果你是一個代理之後,你應該使用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網絡安全網關。

如果不是這樣,這裏有一些其他常見的頭我見過: