背景:
前兩天項目支付這塊遇到個問題,支付成功率下跌的很厲害,最后查清原因是因為我們獲取的”用戶IP“被GC的風控攔截了,什么?攔截了,那還支付個毛啊,別急,待我接下來慢慢道出原因。根本原因是我們最近使用了CDN(Content Deliver Content 全稱內容分發網絡),CDN相當於是代理服務器,我們獲取的所有用戶IP其實都是CDN服務器的IP,也難怪被風控了呢,那具體怎么解決呢。
解決方案:
首先運營商一般都會講用戶IP轉發給Web應用,那么方法1:是使用運營商的插件來獲取真實IP;方法2:通過判斷 HTTP_X_FORWARDED_FOR 來判斷到達Web應用的請求是否通過了代理;下面介紹下代碼獲取用戶請求的真實IP:
/// <summary> /// 用於獲取因用cdn無法獲取用戶真實IP的方法 /// </summary> /// <returns></returns> public string GetCdnIp() { try { if (HttpContext.Current == null || HttpContext.Current.Request == null || HttpContext.Current.Request.ServerVariables == null) return ""; string customerIP = ""; //CDN加速后取到的IP simone 090805 customerIP = HttpContext.Current.Request.Headers["Cdn-Src-Ip"]; if (!string.IsNullOrEmpty(customerIP)) { return customerIP; } if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null) { customerIP = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (customerIP == null) customerIP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } else { customerIP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } if (string.Compare(customerIP, "unknown", true) == 0) return HttpContext.Current.Request.UserHostAddress; return customerIP;
上面是網上的資料,再來看看咱本地的代碼是如何獲取的:
/// <summary> /// 獲取用戶真實IP /// </summary> /// <returns></returns> public static string GetIPFromHttpXForwardedFor() { HttpRequest request = HttpContext.Current.Request; string result = request.Headers["X-Forwarded-For"]; if (!string.IsNullOrEmpty(result)) { int index = result.IndexOf(".", StringComparison.Ordinal); //可能有代理 if (index == -1)//沒有"."肯定是非IPv4格式 { if (!IsIpAddress(result))//代理不是IP格式 { result = null; } } else { //有",",估計多個代理。取第一個不是內網的IP。 result = result.Replace(" ", "").Replace("\"", ""); string[] tempIps = result.Split(",;".ToCharArray()); foreach (string temp in tempIps) { if (IsIpAddress(temp) && temp.Substring(0, 3) != "10." && temp.Substring(0, 7) != "192.168" && temp.Substring(0, 7) != "172.16.") { return temp;//找到不是內網的地址 } } } } if (string.IsNullOrEmpty(result)) { result = request.ServerVariables["HTTP_X_FORWARDED_FOR"]; } if (string.IsNullOrEmpty(result)) { result = request.ServerVariables["REMOTE_ADDR"]; } if (string.IsNullOrEmpty(result)) { result = request.UserHostAddress; } if (result == "::1") { result = "127.0.0.1"; } return result; }
思考
:
在網上還看了一些資料,說 HTTP_X_FORWARDED_FOR 是擴展頭,所以還沒有成為一個標准,還有如果要將HTTP_X_FORWARDED_FOR作為用戶的真實IP那么需要判斷可信CDN的IP范圍,才能保證你所獲取的IP是真實的而不是偽造過的。
參考資料: