【IT168 技术文档】
目前网上流行的所谓“取真实ip地址”的方法,都有bug,没有考虑到多层透明代理的情况。多数代码类似:
stringIpAddress=(HttpContext.Current.Request. ServerVariables["HTTP_X_FORWARDED_FOR"]!=null &&HttpContext.Current.Request.ServerVariables ["HTTP_X_FORWARDED_FOR"]!=String.Empty) ?HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] :HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
事实上,上面的代码只试用与用户只使用了1层代理,如果用户有2层,3层http_x_forwarded_for的值是:“本机真实IP,1层代理IP,2层代理IP,……”,如果这个时候你的数据中保存IP字段的长度很小(15个字节),数据库就报错了。
实际应用中,因为使用多层透明代理的情况比较少,所以这种用户并不多。其他应用情况,现在越来越多的网站使用了代理加速方式,比如新浪、SOHU的新闻都使用Squid做代理方式,利用多台服务器分流。Squid本身类似透明代理,会发送“HTTP_X_FORWARDED_FOR”,HTTP_X_FORWARDED_FOR中包括客户的IP地址,如果此时客户已经使用了一层透明代理,那么程序取的“HTTP_X_FORWARDED_FOR”就包括两个IP地址。(我遇到过3个IP地址的情况,4个的未遇到过)
所以取“真正”IP地址的方式,还应该判断“HTTP_X_FORWARDED_FOR”中是否有“,”逗号,或者长度是否超长(超过15字节xxx.xxx.xxx.xxx)。
/**////<summary> ///取得客户端真实IP。如果有代理则取第一个非内网地址 ///</summary> publicstaticstringIPAddress { get { stringresult=String.Empty; result=HttpContext.Current.Request. ServerVariables["HTTP_X_FORWARDED_FOR"]; if(result!=null&&result!=String.Empty) { //可能有代理 if(result.IndexOf(".")==-1)//没有“.”肯定是非IPv4格式 result=null; else { if(result.IndexOf(",")!=-1) { //有“,”,估计多个代理。取第一个不是内网的IP。 result=result.Replace("","").Replace("'",""); string[]temparyip=result.Split(",;".ToCharArray()); for(inti=0;i<temparyip.Length;i++) { if(Text.IsIPAddress(temparyip[i]) &&temparyip[i].Substring(0,3)!="10." &&temparyip[i].Substring(0,7)!="192.168" &&temparyip[i].Substring(0,7)!="172.16.") { returntemparyip[i];//找到不是内网的地址 } } } elseif(Text.IsIPAddress(result))//代理即是IP格式 returnresult; else result=null;//代理中的内容非IP,取IP } } stringIpAddress=(HttpContext.Current.Request. ServerVariables["HTTP_X_FORWARDED_FOR"]!=null&&HttpContext. Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]!= String.Empty)?HttpContext.Current.Request.ServerVariables ["HTTP_X_FORWARDED_FOR"]:HttpContext.Current.Request. ServerVariables["REMOTE_ADDR"]; if(null==result||result==String.Empty) result=HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; if(result==null||result==String.Empty) result=HttpContext.Current.Request.UserHostAddress; returnresult; } }
取“HTTP_X_FORWARDED_FOR”的弊端:
HTTP_X_FORWARDED_FOR是HTTP协议中头的一部分,不影响TCP的通讯。也就是说实际上客户端可以发送任意内容的HTTP_X_FORWARDED_FOR,以就是伪造IP。最简单的是WEB程序的IP记录,本来是要记录真实IP的,反而被“黑客”欺骗。当你的应用程序记录客户的访问IP、拒绝或允许部分IP的访问、错误日志都会出错,甚至误杀。