说一哈,我也是转来的,不是想骗PV,方便自己查而已!

目前网上流行的所谓"取真实IP地址"的方法,都有bug,没有考虑到多层透明代理的情况。 
多数代码类似:

string IpAddress = (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)。

所以代码应该如下:

  1. /**//// <summary>
  2. /// 取得客户端真实IP。如果有代理则取第一个非内网地址
  3. /// </summary>
  4. public static string IPAddress
  5. {
  6. get
  7. {
  8. string result = String.Empty;
  9. result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
  10. if(result!=null&&result!= String.Empty)
  11. {
  12. //可能有代理
  13. if(result.IndexOf(".")==-1)    //没有"."肯定是非IPv4格式
  14. result = null;
  15. else
  16. {
  17. if(result.IndexOf(",")!=-1)
  18. {
  19. //有",",估计多个代理。取第一个不是内网的IP。
  20. result = result.Replace(" ","").Replace(""","");
  21. string[] temparyip = result.Split(",;".ToCharArray());
  22. for(int i=0;i<temparyip.Length;i++)
  23. {
  24. if( Text.IsIPAddress(temparyip[i])
  25. && temparyip[i].Substring(0,3)!="10."
  26. && temparyip[i].Substring(0,7)!="192.168"
  27. && temparyip[i].Substring(0,7)!="172.16.")
  28. {
  29. return temparyip[i];    //找到不是内网的地址
  30. }
  31. }
  32. }
  33. else if(Text.IsIPAddress(result)) //代理即是IP格式
  34. return result;
  35. else
  36. result = null;    //代理中的内容 非IP,取IP
  37. }
  38. }
  39. string IpAddress = (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"];
  40. if (null == result || result == String.Empty)
  41. result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
  42. if (result == null || result == String.Empty)
  43. result = HttpContext.Current.Request.UserHostAddress;
  44. return result;
  45. }
  46. }

取"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格式检查也是不可少的。

附:(Text是我自定义的一个类,IsIPAddress是其中的一个判断是否是IP地址格式的方法)

  1. #region bool IsIPAddress(str1) 判断是否是IP格式
  2. /**//// <summary>
  3. /// 判断是否是IP地址格式 0.0.0.0
  4. /// </summary>
  5. /// <param name="str1">待判断的IP地址</param>
  6. /// <returns>true or false</returns>
  7. public static bool IsIPAddress(string str1)
  8. {
  9. if(str1==null||str1==string.Empty||str1.Length<7||str1.Length>15) return false;
  10. string regformat = @"^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$";
  11. Regex regex = new Regex(regformat,RegexOptions.IgnoreCase );
  12. return regex.IsMatch(str1);
  13. }
  14. #endregion

C#取真实IP地址及分析的更多相关文章

  1. 穿过代理服务器取远程用户真实IP地址

    public static string GetIP() { string str = ""; //穿过代理服务器取远程用户真实IP地址: if (System.Web.HttpC ...

  2. 查找“CDN、负载均衡、反向代理”等大型网络真实IP地址的方法

    首先,CDN.负载均衡.反向代理还分为很多层,有时查出来的是最外层的 CDN 服务器群,真实的机器是不对外开放的,类似这样的: 用户 → CDN 网络 → 一台或多台真实机器 ↗ CDN Server ...

  3. CDN下nginx获取用户真实IP地址

    随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:nginx如何获取用户 ...

  4. 多级反向代理下,Java获取请求客户端的真实IP地址多中方法整合

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  5. Java获取客户端真实IP地址的两种方法

    在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实I ...

  6. php获取真实ip地址(转)

    REMOTE_ADDR只能获取访问者本地连接中设置的IP,如中南民族大学校园网中自己设置的10.X.XXX.XXX系列IP,而这个函数获取的是局域网网关出口的IP地址, 如果访问者使用代理服务器,将不 ...

  7. 获得用户的真实IP地址

    /** * 获得用户的真实IP地址 * * @access public * @return string */if (!function_exists('get_real_ip')){ functi ...

  8. JSP 获取真实IP地址的代码

    [转载]JSP 获取真实IP地址的代码 JSP 获取真实IP地址的代码 在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.   ...

  9. Java获取请求客户端的真实IP地址

    整理网友的材料,最后有源码,亲测能解决所有java获取IP真实地址的问题 整理的这里: 1.链接1 2.链接2 JSP里,获取客户端的IP地址的方法是: request.getRemoteAddr() ...

随机推荐

  1. bzoj1013

    这道题题解太多,只贴代码. #include<cstdio> #include<cmath> #include<algorithm> using namespace ...

  2. 把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend

    //把一个序列转换成严格递增序列的最小花费 CF E - Sonya and Problem Wihtout a Legend //dp[i][j]:把第i个数转成第j小的数,最小花费 //此题与po ...

  3. jquery选择器的使用

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  4. Python伪开发者对于搜狐云景的测评

    Python伪开发者对于搜狐云景的测评 本人是GAE和OpenShift的狂热爱好者,玩过各种国外PaaS.某次想搞个稍微复杂点的Python Web程序,需要比较好的网络传输速度,就试图找前PM(P ...

  5. home-brew 安装&下载

    安装: ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&qu ...

  6. C#.Net 导出Excel 之单元格 相关设置

    range.NumberFormatLocal = "@";     //设置单元格格式为文本range = (Range)worksheet.get_Range("A1 ...

  7. 创建并使用Windows Azure虚拟机模板

    在现实的IaaS应用中,往往会创建自己的虚拟机映像模板,以满足快速应用部署的目标,如预先配置好某些应用.管理与监控管理等. 1.登录到Windows Azure Dashboard中创建一个做为模板的 ...

  8. HD2043猜密码

    密码 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission ...

  9. Mysql SQL优化&执行计划

    SQL优化准则 禁用select * 使用select count(*) 统计行数 尽量少运算 尽量避免全表扫描,如果可以,在过滤列建立索引 尽量避免在where子句对字段进行null判断 尽量避免在 ...

  10. 查看80端口被占用的方法(IIS、apmserv、system)

    端口如果被其他程序占用就不能正常启动,比如有时启动时会提示WEB启动失败,其实就是80 端口被占用了,而迅雷等下载软件恰恰就是占用了80端口,关掉就行了.但有时迅雷等都没有开 也启动不了,那就是别的东 ...