更進一步來說,可能會聽到資安專家,直接要你死了這條心,在網路世界裡,是無法找到真實 IP的,因為網路封包的標頭都是可以假冒的,也就是說,你抓到的 IP ,有可能是假的。有許多論壇的網站,都很習慣將發表文章的作者 IP 連同文章內容一起公開,也就是說,該網站的運作方式,會去抓 User 的 IP ,然後存進資料庫。這動作,曾經讓不安好心的人起了個念頭。假設這個站台不注重資安,是用了
string sql = "INSERT INTO (IP) VALUE ('" + IP + "')";
這寫法, 會讓有心人士將 HTTP 標頭裡將原先紀錄 IP 位址的地方改成惡意的SQL 指令碼,那當你的系統在執行儲存 IP 動作時,也同時執行了惡意程式碼。而這一點,是所有準備要留下 IP 紀錄的工程師,必須要考慮的一個安全議題。當然,養成好習慣,驗證你所要傳給 SQL 的參數內容,是自保的不二法門。
以下提供網友提供的驗證是否為合法 IP 的 Regular :
^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$
用 C# 寫成 CheckIP( )
///
/// 檢查 IP 是否合法
///
/// strPattern:需檢測的 IP
/// true:合法 false:不合法
private bool CheckIP(string strPattern)
{
// regular: ^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$
Regex regex = new Regex("^\\d{1,3}[\\.]\\d{1,3}[\\.]\\d{1,3}[\\.]\\d{1,3}$");
Match m = regex.Match(strPattern);
return m.Success;
}
撇開特別的情況,抓真實 IP 的功能,還是得寫,總不能讓你無法跟老闆交待吧!但記得要先跟他打預防針,讓他理解到,無法保證百分百取得真實 IP,因為 IP 有可能被假冒,但正常情況下,取得大多數的使用者 IP 則是可行的。
假設使用者沒有透過代理伺服器,則使用 Request.ServerVariables["REMOTE_ADDR"] 就可以抓到 IP;但如果有透過代理伺服器,則要改成使用 Request.ServerVariables["HTTP_X_FORWARDED_FOR"]。而在kingwkb的专栏 的一篇文章「[hidotnet]真正的取真实IP地址及利弊」提到,如果使用者的環境是使用多重代理伺服器時,則使用Request.ServerVariables["HTTP_X_FORWARDED_FOR"] 會得到「真實IP,第一層代理IP,第二層代理IP,...」(ex:「140.134.4.4,140.134.4.250,140.128.2.10」)的結果。而 kingwkb 文章也進一步去將所謂內部 IP 的資訊事先在程式中進行了篩選,只留下相對可信的資訊。
最後整理了測試程式,結果如下:
撰寫了 GetIP( ) 函式來取得真實 IP,並搭配 CheckIP( ) 來驗證所抓的 IP 是否合法。
protected void Page_Load(object sender, EventArgs e)
{
//自己定義的 Label,用來顯示 IP 訊息
lbIP.Text = GetIP();
}
private string GetIP()
{
string ip;
string trueIP=string.Empty;
//先取得是否有經過代理伺服器
ip=Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!string.IsNullOrEmpty(ip))
{
//將取得的 IP 字串存入陣列
string[] ipRange = ip.Split(',');
//比對陣列中的每個 IP
for (int i = 0; i < ipRange.Length; i++)
{
//剔除內部 IP 及不合法的 IP 後,取出第一個合法 IP
if (ipRange[i].Trim().Substring(0, 3) != "10." &&
ipRange[i].Trim().Substring(0, 7) != "192.168" &&
ipRange[i].Trim().Substring(0, 7) != "172.16." &&
CheckIP(ipRange[i].Trim()))
{
trueIP = ipRange[i].Trim();
break;
}
}
}
else
{
//沒經過代理伺服器,直接使用 ServerVariables["REMOTE_ADDR"]
//並經過 CheckIP( ) 的驗證
trueIP = CheckIP(Request.ServerVariables["REMOTE_ADDR"])?
Request.ServerVariables["REMOTE_ADDR"]:"";
}
return trueIP;
}
/// <summary>
/// 檢查 IP 是否合法
/// </summary>
/// <param name="strPattern">需檢測的 IP</param>
/// <returns>true:合法 false:不合法</returns>
private bool CheckIP(string strPattern)
{
// 繼承自:System.Text.RegularExpressions
// regular: ^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$
Regex regex = new Regex("^\\d{1,3}[\\.]\\d{1,3}[\\.]\\d{1,3}[\\.]\\d{1,3}$");
Match m = regex.Match(strPattern);
return m.Success;
}
參考文章:
01:[hidotnet]真正的取真实IP地址及利弊
02:使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果
03:PHP利用HTTP_X_FORWARDED_FOR抓取訪客ip
04:How to get client “IP Address” using Asp.net /C#
沒有留言:
張貼留言