2009-02-09 13 views
54

Tôi hiểu đó là một thực hành tiêu chuẩn để xem xét cả hai biến này. Tất nhiên họ có thể dễ dàng bị giả mạo. Tôi tò mò có bao lâu bạn có thể mong đợi những giá trị này (đặc biệt là các HTTP_X_FORWARDED_FOR) để chứa thông tin chính hãng và không chỉ được tranh giành hoặc có giá trị của họ bị tước đi?Nhận địa chỉ IP của khách hàng: REMOTE_ADDR, HTTP_X_FORWARDED_FOR, điều gì khác có thể hữu ích?

Bất kỳ ai có kinh nghiệm hoặc thống kê về nội dung này?

Có điều gì khác có thể hữu ích cho nhiệm vụ nhận địa chỉ IP của khách hàng không?

+0

Lưu ý câu hỏi và câu trả lời đều sử dụng tiền tố HTTP_ là một chi tiết triển khai cụ thể của ASP.NET v1.0-v4.x, khi tiêu đề yêu cầu HTTP được thêm vào bộ sưu tập ServerVariables. Một ví dụ khác là REMOTE_ADDR, trong đó có API riêng của nó trong ASP.NET Core. https://stackoverflow.com/questions/28664686/how-do-i-get-client-ip-address-in-asp-net-core – yzorg

Trả lời

26

Tùy thuộc vào bản chất của trang web của bạn.

Tôi tình cờ làm việc trên một phần mềm mà theo dõi IP là quan trọng và trong một trường được các trang web giới hạn sử dụng, tôi đoán khoảng 20% ​​- 40% yêu cầu là IP hoặc tiêu đề giả mạo bị phát hiện, tùy thuộc vào vào thời gian trong ngày và họ đến từ đâu. Đối với một trang web có lưu lượng truy cập không phải trả tiền (nghĩa là không thông qua đối tác), tôi mong đợi tỷ lệ IP tốt hơn nhiều.

Như Kosi đã nói, hãy cẩn thận những gì bạn đang làm với điều này - IP không phải là cách đáng tin cậy để xác định khách truy cập duy nhất.

7

Không có câu trả lời thực sự cho câu hỏi của bạn nhưng:
Thường dựa vào địa chỉ IP của khách hàng, theo ý kiến ​​của tôi không phải là thực hành tốt vì không thể xác định khách hàng theo cách độc đáo.

vấn đề trên đường là rằng có khá một kịch bản rất nhiều nơi chỉ IP không thực sự gắn kết với một khách hàng:

  • Proxy/Webfilter (mangle hầu như tất cả mọi thứ)
  • Anonymizer mạng (không có cơ hội ở đây một trong hai)
  • NAT (một IP nội bộ không phải là rất hữu ích cho bạn)
  • ...

tôi không thể đưa ra một y thống kê về số lượng địa chỉ IP là trung bình đáng tin cậy nhưng những gì tôi có thể cho bạn biết rằng gần như không thể biết liệu địa chỉ IP đã cho có phải là địa chỉ khách hàng thực hay không.

+0

Cách nào là 'các phương pháp hay nhất' để * xác định khách hàng theo kiểu thời trang độc đáo *? *** Danh sách kiểm tra ***: _Không sử dụng máy khách IP address_ – Kiquenet

2

IP + "Tác nhân người dùng" có thể tốt hơn cho khách truy cập duy nhất.

+0

nah, tác nhân người dùng không phải là rất đa dạng và giả mạo rộng rãi anyway – annakata

+5

giả mạo rộng rãi, nhưng nói chung họ không thay đổi từ yêu cầu để yêu cầu - http: //panopticlick.eff .org/ – wprl

55

Ngoài REMOTE_ADDRHTTP_X_FORWARDED_FOR có một số tiêu đề khác có thể được thiết lập như:

  • HTTP_CLIENT_IP
  • HTTP_X_FORWARDED_FOR có thể dấu phẩy phân cách danh sách các IP
  • HTTP_X_FORWARDED
  • HTTP_X_CLUSTER_CLIENT_IP
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED

tôi thấy mã trên trang web sau đây hữu ích:
http://www.grantburton.com/?p=97

+0

Danh sách này có hoàn thành không, nghĩa là nó chiếm hơn 90% tổng số proxy? – basZero

+4

Tôi không nghĩ rằng các tiêu đề đó nên có tiền tố HTTP_ ... một chút tìm kiếm được bật lên http://stackoverflow.com/questions/3834083/http-headers-what-is-the-difference-between-x-forwarded -for-x-forwarded-for-a – lmsurprenant

+0

Hiện cũng có một Người giới thiệu, theo [RFC 7239] (https://tools.ietf.org/html/rfc7239) – Kevin

10

Tôi đã mã PHP được chuyển Grant Burton của một phương pháp tĩnh ASP.Net callable so với HttpRequestBase. Nó sẽ tùy chọn bỏ qua bất kỳ phạm vi IP riêng.

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

Cảm ơn bạn đã viết mã. Tuy nhiên, có một vài vấn đề với nó.Đầu tiên, có thêm 'return false;' trong 'ValidIP'. Thứ hai, lớp IpRange không thực sự xử lý IPV6 vì địa chỉ IPV6 là 128 bit. Có lẽ 'System.Numerics.BigInteger' từ .NET 4 có thể được sử dụng, nhưng nó cũng có thể là phạm vi riêng tư ít thú vị hơn với IPV6 anyway (?). –

+1

Ồ, và một vấn đề khác: Thay vì kiểm tra tiêu đề từ request.Headers, tôi nghĩ rằng bạn muốn request.ServerVariables. Cái sau có các khóa như 'HTTP_X_FORWARDED_FOR' trong khi cái trước chỉ là' X-Forwarded-For'. –

+0

Sẽ tuyệt vời nếu điều này cũng hỗ trợ [RFC 7239] (https://tools.ietf.org/html/rfc7239): D – Kevin

1

Nếu bạn đằng sau một proxy, bạn nên sử dụng X-Forwarded-For: http://en.wikipedia.org/wiki/X-Forwarded-For

Nó là một IETF draft standard với sự hỗ trợ rộng:

The X-Forwarded-For lĩnh vực được hỗ trợ bởi hầu hết các máy chủ proxy, bao gồm Mực, Apache mod_proxy, Bảng Anh, HAProxy, Bộ nhớ cache Varnish, Thiết bị bảo mật web IronPort, AVANU WebMux, ArrayNetworks, AppDirector của Radware và bộ ADC Alteon, ADC-VX, a nd ADC-VA, F5 Big-IP, Proxy màu xanh da trời, Công cụ bộ nhớ cache của Cisco, Cổng Web McAfee, Khóa máy bay Phion , Bảo mật quan trọng của Finjan, NetApp NetCache, jetNEXUS, Crescendo Maestro, Web Adjuster và Websense Web Security Gateway.

Nếu không, đây là một vài tiêu đề phổ biến khác mà tôi đã nhìn thấy: