天天看點

Get Client IPHow 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 

How to get a user's client IP address in ASP.NET?

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