Get Client IP How to get a user's client IP address in ASP.NET? What is the difference between Request.UserHostAddress and Request.ServerVariables[“REMOTE_ADDR”].ToString() 【干货分享】获取用户IP的正确姿势 ASP.NET获取用户端的真实IP 

Often you will want to know the IP address of someone visiting your website. While ASP.NET has several ways to do this one of the best ways we've seen is by using the "HTTP_X_FORWARDED_FOR" of the ServerVariables collection.

Here's why...

Sometimes your visitors are behind either a proxy server or a router and the standard Request.UserHostAddress only captures the IP address of the proxy server or router. When this is the case the user's IP address is then stored in the server variable ("HTTP_X_FORWARDED_FOR").

So what we want to do is first check "HTTP_X_FORWARDED_FOR" and if that is empty we then simply return ServerVariables("REMOTE_ADDR").

While this method is not foolproof, it can lead to better results. Below is the ASP.NET code in VB.NET, taken from James Crowley's blog post "Gotcha: HTTP_X_FORWARDED_FOR returns multiple IP addresses"

protected string GetIPAddress()
{
    System.Web.HttpContext context = System.Web.HttpContext.Current; 
    string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

    if (!string.IsNullOrEmpty(ipAddress))
    {
        string[] addresses = ipAddress.Split(',');
        if (addresses.Length != 0)
        {
            return addresses[0];
        }
    }

    return context.Request.ServerVariables["REMOTE_ADDR"];
}
 
Be sure to not use this code for security purposes because anyone can fake HTTP_X_FORWARDED_FOR or similar headers. So if you use this for security related logging or security checks, an attacker can bypass it easily.

版本二   考虑了代理

 private string GetUserIP(NameValueCollection serverVariables)
        {
            string userIp;
            if (serverVariables["HTTP_VIA"] != null)
            {
                var ip = serverVariables["HTTP_X_FORWARDED_FOR"];
                if (ip != null)
                {
                    userIp = ip.Split(',')[0];
                }
                else
                {
                    userIp = serverVariables["REMOTE_ADDR"];
                }
            }
            else
            {
                userIp = serverVariables["REMOTE_ADDR"];
            }
            return userIp;
        }

版本三  考虑HTTP_X_REAL_IP

private string GetIpFromServerVariables(NameValueCollection serverVariables)
        {
            if (serverVariables == null)
            {
                return null;
            }

            var ip = serverVariables["HTTP_X_FORWARDED_FOR"];
            ip = ip?.Split(',')[0];
            if (string.IsNullOrWhiteSpace(ip))
            {
                ip = serverVariables["HTTP_X_REAL_IP"];
            }
            if (string.IsNullOrWhiteSpace(ip))
            {
                ip = serverVariables["REMOTE_ADDR"];
            }
            return ip;
        }

What is the difference between Request.UserHostAddress and Request.ServerVariables[“REMOTE_ADDR”].ToString()

Short answer: The two are identical.

Long answer: To determine the difference between the two use Reflector (or whatever disassembler you prefer).

The code for the HttpRequest.UserHostAddress property follows:

public string UserHostAddress
{
    get
    {
        if (this._wr != null)
        {
            return this._wr.GetRemoteAddress();
        }
        return null;
    }
}

Note that it returns _wr.GetRemoteAddress(). The _wr variable is an instance of an HttpWorkerRequest object. There are different classes derived from HttpWorkerRequest and which one is used depends on whether you are using IIS 6, IIS 7 or beyond, and some other factors, but all of the ones you would be using in a web application have the same code for GetRemoteAddress(), namely:

public override string GetRemoteAddress()
{
    return this.GetServerVariable("REMOTE_ADDR");
}

As you can see, GetRemoteAddress() simply returns the server variable REMOTE_ADDR.

As far as which one to use, I'd suggest the UserHostAddress property since is doesn't rely on "magic strings."

Happy Programming

【干货分享】获取用户IP的正确姿势

如何获取用户的IP,这个需求简直是太常见了,像登录入口,注册入口,投票,日志记录,api接口中判断同一个ip单位时间内的请求数,可是怎么去获取用户的真实IP呢?

网上的代码很多,好多人直接拿来就用,却没有想到带来了很大的安全问题。

1.代码示例

这是网上的一个示范例子,我们很多同事也这么写,上面这个例子是php实现的,由于HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,HTTP_VIA (经过的 Proxy)这些以HTTP打头的server变量都是用户可控的,由此可导致xss,认证绕过等缺陷。

下面我们看下python的例子:

也是由于客户端变量可控导致获取的ip可为任意值。在此例中,X-Real-IP是nginx特有的,通过配置proxy_set_header X-Real-IP $remote_addr;从REMOTE_ADDR中取值。

2 X-Forwarded-For和 REMOTE_ADDR的区别

REMOTE_ADDR代表着客户端的IP,但是这个客户端是相对服务器而言的,也就是实际上与服务器相连的机器的IP(建立tcp连接的那个),这个值是不可伪造的,如果没有代理的话,这个值就是用户实际的IP值,有代理的话,用户的请求会经过代理再到服务器,这个时候REMOTE_ADDR会被设置为代理机器的IP值
正如前面所说,有了代理就获取不了用户的真实IP,由此X-Forwarded-For应运而生,它是一个非正式协议,在请求转发到代理的时候代理会添加一个X-Forwarded-For头,将连接它的客户端IP(也就是你的上网机器IP)加到这个头信息里,这样末端的服务器就能获取真正上网的人的IP了。
假设用户的请求顺序如下:
网民电脑ip->代理服务器1–>代理服务器2–>目标服务器
REMOTE_ADDR:代理服务器2的IP值
X-Forwarded-For就是:网民电脑IP,代理1的IP,代理2的IP
在这里只有REMOTE_ADDR是可信的,其他从客户端获取的数据都是不可信的,都是可伪造的。下面简单示例下一个篡改X-Forwarded-For的情况:

3 正确的代码示例

在X-Forwarded-For信息头中可以提取真实的用户IP,但是这个IP是可以伪造的,如果从X-Forwarded-For提取IP作为用户的IP对于存在登录次数,api速率限制等一些接口是致命的缺陷,因为任意构造出无数的合法或者非法IP地址。

而REMOTE_ADDR只是服务器前端的IP地址,如果没有代理就是用户的真实地址。这个是不可伪造的,而且代理是有限的,可以基于此来获取IP。在wordpress中,获取客户的IP地址代码如下:

4 总结
X-Forwarded-For可被用户伪造,不应该被信任;REMOTE_ADDR是使用“REMOTE_ADDR”机器的前一个建立tcp连接的机器的地址,是不可伪造的,在无代理时可以理解为用户的IP地址,有反向代理时,先将REMOTE_ADDR赋给X-Real-IP,最后可以从X-Real-IP中获取用户的IP。

参考文献:
http://gong1208.iteye.com/blog/1559835
http://devco.re/blog/2014/06/19/client-ip-detection/
http://blog.pengqi.me/2013/04/20/remote-addr-and-x-forwarded-for/

ASP.NET获取用户端的真实IP 

改进版获取用户真实IP

/// <summary>
        /// 取得客户端真实IP。如果有代理则取第一个非内网地址
        /// Author:codeo.cn
        /// </summary>
        /// <returns></returns>
        public static string GetIPAddress()
        {
            string strresult = string.Empty;
            strresult = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if (strresult != null && strresult != string.Empty)
            {
                //可能有代理  
                if (strresult.IndexOf(".") == -1)    //没有“.”肯定是非IPv4格式  
                {
                    strresult = null;
                }
                else
                {
                    if (strresult.IndexOf(".") != -1)
                    {
                        //有“,”,估计多个代理。取第一个不是内网的IP。    
                        strresult = strresult.Replace(" ", "").Replace("'", "");
                        string[] strarrtemparyip = strresult.Split(",;".ToCharArray());

                        for (int i = 0; i < strarrtemparyip.Length; i++)
                        {
                            if (IsIPAddress(strarrtemparyip[i]) && strarrtemparyip[i].Substring(0, 3) != "10." && strarrtemparyip[i].Substring(0, 7) != "192.168" && strarrtemparyip[i].Substring(0, 7) != "172.16.")
                            {
                                return strarrtemparyip[i];    //找到不是内网的地址  
                            }
                        }
                    }
                    else if (IsIPAddress(strresult))    //代理即是IP格式  
                    {
                        return strresult;
                    }
                    else
                    {
                        strresult = null;       //代理中的内容 非IP,取IP
                    }
                }
            }
            string strIpAddress = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != string.Empty ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]);

            if (null == strresult || strresult == string.Empty)
            {
                strresult = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            }
            if (strresult == null || strresult == string.Empty)
            {
                strresult = HttpContext.Current.Request.UserHostAddress;
            }

            return strresult;
        }
        /// <summary>
        /// 判断是否是IP地址格式 0.0.0.0 
        /// Author:codeo.cn  
        /// </summary>
        /// <param name="strIp">待判断的IP地址</param>
        /// <returns>true or false</returns>
        private static bool IsIPAddress(string strIp)
        {
            if (strIp == null || strIp == string.Empty || strIp.Length < 7 || strIp.Length > 15)
            {
                return false;
            }

            string strRegformat = @"^d{1,3}[.]d{1,3}[.]d{1,3}[.]d{1,3}___FCKpd___0quot";

            Regex regex = new Regex(strRegformat, RegexOptions.IgnoreCase);

            return regex.IsMatch(strIp);
        }