取IP的函數有PageRequestUserHostAddress 簡單好用但有時取不到真正IP
目前網上流行的所謂取真實IP地址的方法都有bug沒有考慮到多層透明代理的情況
多數代碼類似
string IpAddress = (HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR]!=null
&& HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR] !=StringEmpty)
?HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR]
:HttpContextCurrentRequestServerVariables[REMOTE_ADDR];
事實上上面的代碼只試用與用戶只使用了層代理如果用戶有層層HTTP_X_FORWARDED_FOR 的值是本機真實IP層代理IP層代理IP 如果這個時候你的數據中保存IP字段的長度很小(個字節)數據庫就報錯了
實際應用中因為使用多層透明代理的情況比較少所以這種用戶並不多
其他應用情況現在越來越多的網站使用了代理加速方式比如 新浪SOHU的新聞 都使用Squid做代理方式利用多台服務器分流Squid本身類似透明代理會發送HTTP_X_FORWARDED_FOR HTTP_X_FORWARDED_FOR 中包括客戶的IP地址如果此時客戶已經使用了一層透明代理那麼程序取的 HTTP_X_FORWARDED_FOR 就包括兩個IP地址(我遇到過個IP地址的情況個的未遇到過)
所以取真正IP地址的方式還應該判斷 HTTP_X_FORWARDED_FOR 中是否有逗號或者長度是否超長(超過字節 xxxxxxxxxxxx)
所以代碼應該如下
/**//// <summary>
/// 取得客戶端真實IP如果有代理則取第一個非內網地址
/// </summary>
public static string IPAddress
{
get
{
string result = StringEmpty;
result = HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR];
if(result!=null&&result!= StringEmpty)
{
//可能有代理
if(resultIndexOf()==) //沒有肯定是非IPv格式
result = null;
else
{
if(resultIndexOf()!=)
{
//有估計多個代理取第一個不是內網的IP
result = resultReplace( )Replace();
string[] temparyip = resultSplit(;ToCharArray());
for(int i=;i<temparyipLength;i++)
{
if( TextIsIPAddress(temparyip[i])
&& temparyip[i]Substring()!=
&& temparyip[i]Substring()!=
&& temparyip[i]Substring()!=)
{
return temparyip[i]; //找到不是內網的地址
}
}
}
else if(TextIsIPAddress(result)) //代理即是IP格式
return result;
else
result = null; //代理中的內容 非IP取IP
}
}
string IpAddress = (HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR]!=null && HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR] !=StringEmpty)?HttpContextCurrentRequestServerVariables[HTTP_X_FORWARDED_FOR]:HttpContextCurrentRequestServerVariables[REMOTE_ADDR];
if (null == result || result == StringEmpty)
result = HttpContextCurrentRequestServerVariables[REMOTE_ADDR];
if (result == null || result == StringEmpty)
result = HttpContextCurrentRequestUserHostAddress;
return result;
}
}
取HTTP_X_FORWARDED_FOR 的弊端
HTTP_X_FORWARDED_FOR 是HTTP協議中頭的一部分不影響TCP的通訊也就是說實際上客戶端可以發送任意內容的 HTTP_X_FORWARDED_FOR以就是偽造IP最簡單的是WEB程序的IP記錄本來是要記錄真實IP的反而被黑客欺騙當你的應用程序記錄客戶的訪問IP拒絕或允許部分IP的訪問錯誤日志 都會出錯甚至誤殺
因此必要的安全日志應該記錄 完整的 HTTP_X_FORWARDED_FOR (至少給數據庫中的字段分配 *+ 個字節以記錄至少個IP) 和 REMOTE_ADDR對 HTTP_X_FORWARDED_FOR 的IP格式檢查也是不可少的
附:(Text是我自定義的一個類IsIPAddress是其中的一個判斷是否是IP地址格式的方法)
#region bool IsIPAddress(str) 判斷是否是IP格式
/**//// <summary>
/// 判斷是否是IP地址格式
/// </summary>
/// <param name=str>待判斷的IP地址</param>
/// <returns>true or false</returns>
public static bool IsIPAddress(string str)
{
if(str==null||str==stringEmpty||strLength<||strLength>) return false;
string regformat = @^\d{}[\]\d{}[\]\d{}[\]\d{}$;
Regex regex = new Regex(regformatRegexOptionsIgnoreCase );
return regexIsMatch(str);
}
#endregion
From:http://tw.wingwit.com/Article/program/net/201311/12367.html