这段取真实 IP 代码有没有需要优化或改进的地方?
欢迎各位大佬批评指正。。谢谢
if (isset($_SERVER)) {
// Use $_SERVER variables by preference
$HTTP_VARS = $_SERVER;
} else if (isset($_ENV)) {
// Fallback to PHP environment variables
$HTTP_VARS = $_ENV;
} else $HTTP_VARS = array();
// Step through the captured $_SERVER or $_ENV array, ignoring the case of the keys.
// (Some "authorities" indicate that the keys can be lower or mixed case!)
$ipAddrList = 'unknown';
foreach($HTTP_VARS as $key => $value) {
$key = strtoupper($key);
$value = str_replace(' ', '', $value);// Get rid of embedded blanks
if ($key == 'HTTP_FORWARDED') {
// We're dealing with the new HTTP Forwarded: by=identifier; for=identifier; host=host; proto=protocol
// See: https://tools.ietf.org/html/rfc7239
$value = str_replace(',for=', ',', strtolower($value)); // Make everything lower-case and then get rid of extraneous "for=" tags
$params = explode(';', $value);// Separate the Forwarded: parameters into an array
foreach ($params as $key => $value) {
if (substr($value,0,4) == 'for=') {
$ipAddrList = substr($value,4);// Everything after "for=" is now a comma-separated list of IPv4 or IPv6 addresses
break;
}
}
break;
}
if ($key == 'HTTP_X_FORWARDED_FOR') {
$ipAddrList = $value;
break;
}
if ($key == 'HTTP_X_FORWARDED') {
$ipAddrList = $value;
break;
}
if ($key == 'HTTP_FORWARDED_FOR') {
$ipAddrList = $value;
break;
}
if ($key == 'HTTP_CLIENT_IP') {
$ipAddrList = $value;
break;
}
if ($key == 'REMOTE_ADDR') {
$ipAddrList = $value;
break;
}
}
$ip = preg_replace('~,.*~', '', $ipAddrList); // Trim everything after the first comma, leaving just the first IPv4 or IPv6 address
$ip = str_replace(array('"', "'"), '', $ip); // Get rid of quotation marks used in some addresses
if (substr($ip,0,1) == '[') {
$ip = preg_replace('~\]:.*~', '', $ip); // Get rid of IPv6 port number that follows closing square bracket
$ip = str_replace(array('[', ']'), '', $ip); // Get rid of square brackets enclosing IPv6 address
} else {
$ip = preg_replace('~:.*~', '', $ip); // Get rid of IPv4 port number that follows last digit of address
}
unset($HTTP_VARS, $key, $value, $params, $ipAddrList); // We don't need this any more
$_SERVER['REMOTE_ADDR'] = $ip;
目前最终方案:1、修改 nginx 配置文件,添加
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-FORWORD-FOR $remote_addr
2、在我贴出的代码上面再加个判断
if ($key == 'HTTP_X_REAL_IP') {
$ipAddrList = $value;
break;
}
目前这样应该没什么问题了。 ----------------------- 以下是精选回复-----------------------
答:能取使用代理的访客的真实 ip ?
答:会有 $_SERVER 函数不存在的情况吗。。
答:建议判断一下反代服务器的 IP 地址,以免请求方直接加 X-FORWADR 头冒充反代随意发送源 IP 地址
答:和反代协商好头就行了,我从不用 X-FORWARD 啥的公开头,这样别人私自发 X-FORWARD 头你还得判断哪个是反代加的哪个是用户私加的
答:直接用 REMOTE_ADDR,或我们可信的请求头(存在反向代理的话)。一来就用 X_FORWARDED_FOR ? 人家都不用去用代理了,直接伪造 X_FORWARDED_FOR 就能绕过系统检测。。
获取真实 IP 感觉是个高深的技术活,贴我一篇早年的 csdn 的帖子,https://bbs.csdn.net/topics/390727207,参考 16、21、32 楼
答:复制粘贴一把梭
答:xff 字段可以随便传
答:上高匿就玩不了了
答:X-FORWORD-FOR 我说错了,应该是最右边那个,但是用户伪造也是妥妥的没问题的,所以多级反代的时候这很难办,只能由最靠近用户的那个反代控制好
答:没有必要写出一个通用的代码,我 PHP 也不怎么会,简单的判断就行了。主要是根据你的程序定,比如你要像 discuz 那种开源出去可能要考虑到所有情况,自己用就随便搞下就没问题的。
如果是要做 IP 查询业务的,比如想穿透 HTTP 代理,可能还要结合自建 dns 啥的技术,只做这些还不够
答:我做过这样的事情,可以看看: https://yonghaowu.github.io/2018/11/23/get_reql_ip/ 从限流谈到伪造 IP nginx remote_addr
答:这段代码明显有漏洞啊。我只要在 HTTP 头里面带某个假 ip 属性,你获取的就都是假的
答:多年 php 不明白为什么获取 IP 搞这么复杂 我都是直接取 remote addr 客户端发来的任何信息都不可信
0条评论