背景:
前两天项目支付这块遇到个问题,支付成功率下跌的很厉害,最后查清原因是因为我们获取的”用户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是真实的而不是伪造过的。
参考资料: