更進一步來說,可能會聽到資安專家,直接要你死了這條心,在網路世界裡,是無法找到真實 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#
沒有留言:
張貼留言