使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果

在WEB开发中.我们可能都习惯使用下面的代码来获取客户端的IP地址:
 -----------------C#代码----------------------------------------------------------------------
//优先取得代理IP 
string IP = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; 
if (string.IsNullOrEmpty(IP)) {
 
//没有代理IP则直接取连接客户端IP 
 IP = Request.ServerVariables["REMOTE_ADDR"]; 
}
 

-----------------------------------------------------------------------------------------------

上面代码看来起是正常的.可惜这里却隐藏了一个隐患!!因为"HTTP_X_FORWARDED_FOR"这个值是通过获取HTTP头的"X_FORWARDED_FOR"属性取得.所以这里就提供给恶意破坏者一个办法:可以伪造IP地址!!

下面是测试代码:
--------------C#代码---------------------------------------------------------------------------
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost/ip.aspx"); 
request.Headers.Add(
"X_FORWARDED_FOR""0.0.0.0"); 
HttpWebResponse response 
= (HttpWebResponse)request.GetResponse(); 
StreamReader stream 
= new StreamReader(response.GetResponseStream()); 
string IP = stream.ReadToEnd(); 
stream.Close(); 
response.Close(); 
request 
= null

-----------------------------------------------------------------------------------------------
"ip.aspx"文件代码:
------------C#代码-----------------------------------------------------------------------------
Response.Clear(); 
//优先取得代理IP 
string IP = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; 
if (string.IsNullOrEmpty(IP))

  
//没有代理IP则直接取客户端IP 
  IP = Request.ServerVariables["REMOTE_ADDR"]; 
}
 
Response.Write(IP); 
Response.End(); 

------------------------------------------------------------------------------------------------
这样.当测试代码中去访问ip.aspx文件时."string IP = stream.ReadToEnd();"这段代码取到的IP数据就是"0.0.0.0"!!!!(呵.在真实情况下.这样的IP地址肯定不是我们想要的结果.而在有些投票系统中限制一个IP只能投1次票时,如果也是用类似的代码取得对方IP然后再判断的话.呵呵.限制就失效咯)...

或者如果你用上面代码获取IP地址后后面又不再进行数据判断的话也许还能更进一步进行数据破坏!!
比如你用类似上面的代码中获取IP地址就直接有这样的SQL语句:
 string sql = "INSERT INTO (IP) VALUE ('" + IP + "')";
那么也许破坏者还可以进行SQL注入进行数据破坏!!

这样看来利用"HTTP_X_FORWARDED_FOR"这个属性获取客户端IP的方法就不再可取了.-_-# 但如果不用这种方法.那么那些真正使用了代理服务器的人.我们又不能再获取到他们的真实IP地址(因为某些代理服务器会在"X_FORWARDED_FOR"这个HTTP头里加上访问用户真正的IP地址).呵.现实就是这样,某种东西都有有得必有失...

最后,我的建议是不要再使用上面的方法去获取客户端IP.即是不要再理会代理情况.你的建议又是怎样呢???
posted @ 2007-11-24 11:06 Kingthy 阅读(6142) 评论(26)  编辑 收藏 网摘 所属分类: Web

  回复  引用  查看    
#1楼[楼主]2007-11-24 11:07 | Kingthy      
我的天..编辑器不见了.就成了这样的排版..汗...
  回复  引用    
#2楼2007-11-24 11:11 | 匿名[未注册用户]
有道理。。。
  回复  引用  查看    
#3楼2007-11-24 11:14 | dudu      
麻烦重新调整一下排版。
  回复  引用  查看    
#4楼[楼主]2007-11-24 11:18 | Kingthy      
现在好了.换了一个编辑就可以了..
"TextBox"这个编辑怎么用不了了??

  回复  引用    
#5楼2007-11-24 11:24 | A1[未注册用户]
呵呵,我用这个骗了不少论坛,搞了不少恶作剧,网上搜一下白宫有哪些IP,然后以此就利用工具(也可以只是浏览器插件FF下比IE容易实现)伪装成从白宫访问,哈哈哈。。。。

回到正题,个人认为还是只支持REMOTE_ADDR比较好。
至于你说的利用伪造HTTP_X_FORWARDED_FOR来实现sql注入,这个貌似02年就被爆出,某个著名的php论坛程序有此漏洞。现在多数论坛程序在处理ip地址的时候都有格式检查,即便没有,在拼接sql语句的时候肯定会过滤不安全字符的(这是最应该做的了)。

  回复  引用  查看    
#6楼[楼主]2007-11-24 11:31 | Kingthy      
@A1
嗯.认同.但现在其时还有很多WEB程序都不会处理这个IP数据的(因为在部分程序员的头脑里IP地址就是XXX.XXX.XXX.XXX.所以认为是数据安全的). :0

  回复  引用  查看    
#7楼2007-11-24 12:02 | 阿不      
还是拼接SQL的错误。
  回复  引用    
#8楼2007-11-24 13:01 | banroo[未注册用户]
老漏洞了。

做好过滤是应该的。

  回复  引用  查看    
#9楼2007-11-24 13:44 | 曲滨*銘龘鶽      
Http Header 本来就是方便传输一些数据的
根本就没有加密

这一点作Web的人应该心知肚明。

  回复  引用  查看    
#10楼2007-11-24 17:15 | Enzo      
@A1
恩,现在都要过滤输入字符!

  回复  引用  查看    
#11楼2007-11-24 20:05 | zoti      
有道理,顶一个。
推荐阅读HTTP协议
  回复  引用  查看    
#13楼2007-11-25 02:30 | 米开朗基罗      
http的头本来就是不可信的,要把它和用户从textbox里面输入的字符串作同等处理。

可以把HTTP_X_FORWARDED_FOR作为一个判断逻辑里面的参考,比较一下看里面是不是已经有了。
其实,限制一个ip只能投一票,它就影响了很多NAT方式共用一个ip的人的正常使用。影响小的是一个家里的人,比如大姐一台电脑,你的一台电脑。两个人,但你们只能投一票。影响大点就是有些垃圾isp,装网的时候就给你一个10.x.x.x,然后让你到它的内部网关路由出去,一堆人用一个ip。

  回复  引用  查看    
#14楼2007-11-25 09:00 | 暗香浮动      
那ip如何获取才是可信的呢。
  回复  引用    
#15楼2007-11-25 11:57 | 5555[未注册用户]
public static string GetRealIP()
{
string ip;
try
{
if (HttpContext.Current.Request.ServerVariables["HTTP_VIA"] != null)
{
ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();
}
else
{
ip = HttpContext.Current.Request.UserHostAddress;
}
}
catch (Exception e)
{
throw e;
}
return ip;
}

用上面的函数获取IP

  回复  引用  查看    
#16楼2007-11-25 13:42 | 米开朗基罗      
@5555
楼上的一行写太多代码了:
ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString().Split(',')[0].Trim();

  回复  引用  查看    
#17楼[楼主]2007-11-25 21:05 | Kingthy      
@米开朗基罗
HTTP头这肯定是不可信的.
@暗香浮动
只有"Request.UserHostAddress"才是可信的.但是这样的话却又获取不了那些已使用了代理服务器的用户真实IP地址(因为在这时Request.UserHostAddress获取到的就是这代理服务器的IP)..

  回复  引用    
#18楼2007-11-25 22:16 | helixapp[未注册用户]
这个看怎么选择了 一般的情况下 特别是使用IE 伪造这个头的可能比较小

假如不判断这个头,作弊者想要找一堆的代理 也不难啊

  回复  引用  查看    
#19楼2007-11-26 00:47 | 米开朗基罗      
@Kingthy
在大众化的产品里面想identify一个用户就是和用户的隐私作搏斗,技术上有很多反追踪的办法的,所以不能完全做到你想要的效果,只可以尽量去堵漏洞,并消除带来的影响。

  回复  引用    
#20楼2007-11-26 16:50 | cozo[未注册用户]
有时候我的程序需要隐藏在自己的Apache的Proxy模块后面,这样如果不用这个方法,取到的IP全部是127.0.0.1。
  回复  引用  查看    
#21楼[楼主]2007-11-28 22:48 | Kingthy      
@cozo
因为你已经知道你的程序是要经过你自己的Proxy,所以基本就可以相信那些数据了..

对了,好像用ASP不行.试一下下面的代码
<%
userip = Request.ServerVariables("HTTP_X_FORWARDED_FOR")
If userip = "" Then userip = Request.ServerVariables("REMOTE_ADDR")
Response.write(userip)
%>
<table>
<% For Each sd In Request.ServerVariables %>
<TR><TD> <%= sd%> </TD>
<TD> <%= Request.ServerVariables(sd) %> </TD>
</TR>
<% Next %>
</table>

  回复  引用    
#23楼2008-10-14 23:49 | fearwall[未注册用户]
public long IPtoNum(string Ip)
{
string[] stringip = new string[4];
stringip = Ip.Split('.');
long ipnum = Convert.ToInt64((stringip[0])) * 16777216 + Convert.ToInt64(stringip[1]) * 65536 + Convert.ToInt64(stringip[2])*256 + Convert.ToInt64(stringip[3]);
return ipnum;
}

  回复  引用    
#24楼2009-03-21 09:06 | 阿嫂法司fasfasf[未注册用户]
sadf
  回复  引用    
#25楼2009-03-21 09:06 | 阿嫂法司fasfasf[未注册用户]
sfasdf




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 970783




相关文章:

相关链接: