前言
我最近在工作中做一个投票功能被刷票了。
虽然这个刷票的bug不是今天文中要说的这个,但这个问题却是我在后续发现的bug,并且很多网上的方法及开源框架中都有这个问题存在,鉴于问题的普遍性,这里有必要说一下。
错误姿势
以下是一个随处可见的获取客户端ip的php函数:
function ip()
{
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
}
return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
}
先读HTTP_CLIENT_IP
,如果没有,再读HTTP_X_FORWARDED_FOR
,还没有,最后读REMOTE_ADDR
。
存在的问题
有什么问题呢?
由于HTTP_CLIENT_IP
和HTTP_X_FORWARDED_FOR
是从HTTP头里面读取出来的,所以,他们是可以伪造的!
伪造IP
我们可以这样伪造这两个值:
$ip = '111.222.111.222';
$header = array(
"CLIENT-IP:{$ip}",
"X-FORWARDED-FOR:{$ip}",
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
那么,用这个获取ip的函数用来限制ip投票就变得毫无意义!
正确姿势
其实我们获取客户端ip只需要用
$_SERVER['REMOTE_ADDR']
就可以了,REMOTE_ADDR
是在TCP连接的时候设定的,是无法进行伪造的。虽然他可能是代理服务器的IP,但无论如何,总比一个可以随意伪造的IP安全得多。
如果您觉得您在我这里学到了新姿势,博主支持转载,姿势本身就是用来相互学习的。同时,本站文章如未注明均为 hisune 原创 请尊重劳动成果 转载请注明 转自: 关于php的获取客户端IP和伪造客户端IP的若干事 - hisune.com
1 Comments