技术开发 频道

真正的取真实IP地址及利弊

【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的访问、错误日志都会出错,甚至误杀。
 
  因此必要的安全日志应该记录完整的HTTP_X_FORWARDED_FOR(至少给数据库中的字段分配3*15+2个字节,以记录至少3个IP)和REMOTE_ADDR。对HTTP_X_FORWARDED_FOR的IP格式检查也是不可少的。
0
相关文章