当前位置:  开发笔记 > 后端 > 正文

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

如何解决《获取客户端IP地址:REMOTE_ADDR,HTTP_X_FORWARDED_FOR,还有什么可能有用?》经验,为你挑选了4个好方法。

我理解这是看待这两个变量的标准做法.当然,他们很容易被欺骗.我很好奇你多久会期望这些价值观(特别是那些HTTP_X_FORWARDED_FOR)包含真实的信息,而不仅仅是被扰乱或者剥夺了他们的价值观?

有这方面经验或统计数据的人吗?

获取客户端IP地址的任务还有什么用处吗?



1> ejunker..:

除此之外REMOTE_ADDR,HTTP_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


我不认为这些标题应该有HTTP_前缀...有点搜索出现http://stackoverflow.com/questions/3834083/http-headers-what-is-the-difference-between-x-forwarded-对于-X-转发换一

2> annakata..:

这取决于您网站的性质.

我碰巧在一些IP跟踪很重要的软件上工作,在分区网站消耗的领域内,我猜大约有20% - 40%的请求是可检测到的欺骗性IP或标头消隐,具体取决于时间那天和他们来自哪里.对于获得有机流量的网站(即不通过合作伙伴),我预计优质IP的比例要高得多.

正如Kosi所说,小心你正在做的事情 - 知识产权绝不是识别独特访客的可靠方式.



3> IDisposable..:

我已经将Grant Burton的PHP代码移植到可以针对HttpRequestBase调用的ASP.Net静态方法中.它可以选择跳过任何私有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;
}

/// 
/// Provides a simple class that understands how to parse and
/// compare IP addresses (IPV4) ranges.
/// 
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")
    };


/// 
/// Describes a header item (key) and if it is expected to be 
/// a comma-delimited string
/// 
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)
    };
}


谢谢你的代码.但是它有几个问题.首先,在`ValidIP`中有一个额外的`return false;`.其次,IpRange类并不真正处理IPV6,因为IPV6地址是128位.也许可以使用.NET 4中的`System.Numerics.BigInteger`,但是对于IPV6来说,私有范围也可能不那么有趣(?).

4> Kosi2801..:

对你的问题没有真正的答案但是:
在我看来,一般依赖客户IP地址并不是一个好的做法,因为它不能以独特的方式识别客户.

道路上的问题是,在很多情况下,IP并没有真正与客户保持一致:

代理/ Webfilter(几乎所有东西)

匿名者网络(这里没有机会)

NAT(内部IP对你来说不是很有用)

...

我无法提供有关平均可靠数量的IP地址的任何统计信息,但我可以告诉您,几乎不可能判断给定IP地址是否是真实客户端地址.

推荐阅读
N个小灰流_701
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有