如上图,是我测试的一段代码访问一个IP查询服务的服务,可以看出,可以任何伪造ip地址!
当前正在做的一个PHP项目,需要验证用户的IP地址是否在授权范围中,请问有什么方法可以避免用户伪造IP?
或者,是否能提供一个其他思路?
补充:实际场景为rest调用,调用和被调用端都为服务器~
想完全避免近乎不可能,透明和匿名http代理还能检测http头,但是socks代理呢,或者自己实现的端口转发呢?
现在能想到的就是维护一个巨大的库,把所有能搜集到的可能是代理的ip加进去,用户访问之前先进库对比。但是这样缺点也很大,一是库太大了访问速度会变慢,影响效率;二是有些ip可能只是暂时是代理,比如肉鸡,可能会恢复正常,比如营运商动态分配的ip,今天我用时做代理,明天分配到你那里就可能不是代理了,如果没有一个很好的检测剔除机制,很可能误杀;三是库不可能把所有代理都收进去,只能尽可能搜集一些互联网上公开的代理,私有代理很难收集到,这些库之外的代理还是没法避免他们访问。
不过目前有公司确实在维护这样的库,对外以api的方式提供服务。
REMOTE_ADDR 没那么容易伪造.
请参见
Can $_SERVER['REMOTE_ADDR'] be trusted?
http://stackoverflow.com/questions/58...
"HTTP_" 开头的$_SERVER很容易伪造.
服务段判断还是挺容易的. 其实下面这个代码也是判断是否使用proxy.
<?php if ( $_SERVER['HTTP_X_FORWARDED_FOR'] || $_SERVER['HTTP_X_FORWARDED'] || $_SERVER['HTTP_FORWARDED_FOR'] || $_SERVER['HTTP_CLIENT_IP'] || $_SERVER['HTTP_VIA'] || in_array($_SERVER['REMOTE_PORT'], array(8080,80,6588,8000,3128,553,554))) || @fsockopen($_SERVER['REMOTE_ADDR'], 80, $errno, $errstr, 30)) { echo "we caught you"; } ?>
结论:服务段最好只取$_SERVER['REMOTE_ADDR']
------------------------小插曲---------------------
最近帮人研究一下discuz的xplus投票系统.
function _get_client_ip() { $clientip = ''; if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { $clientip = getenv('HTTP_CLIENT_IP'); } elseif(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { $clientip = getenv('HTTP_X_FORWARDED_FOR'); } elseif(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { $clientip = getenv('REMOTE_ADDR'); } elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { $clientip = $_SERVER['REMOTE_ADDR']; } preg_match("/[\d\.]{7,15}/", $clientip, $clientipmatches); $clientip = $clientipmatches[0] ? $clientipmatches[0] : 'unknown'; return $clientip; }
呵呵...