zoukankan      html  css  js  c++  java
  • C#取真实IP地址及分析

    *********本人从CSDN上找到的,感觉很有用,就摘过来了**************

    目前网上流行的所谓"取真实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
  • 相关阅读:
    BZOJ 1040 (ZJOI 2008) 骑士
    BZOJ 1037 (ZJOI 2008) 生日聚会
    ZJOI 2006 物流运输 bzoj1003
    ZJOI 2006 物流运输 bzoj1003
    NOI2001 炮兵阵地 洛谷2704
    NOI2001 炮兵阵地 洛谷2704
    JLOI 2013 卡牌游戏 bzoj3191
    JLOI 2013 卡牌游戏 bzoj3191
    Noip 2012 day2t1 同余方程
    bzoj 1191 [HNOI2006]超级英雄Hero——二分图匹配
  • 原文地址:https://www.cnblogs.com/xhyang/p/4026839.html
Copyright © 2011-2022 走看看