获取访客 IP 的正确姿势

2015-10-23 09:06:57 +08:00
 gdtv

1 、先看下教科书上获取 IP 的姿势:

$_SERVER["REMOTE_ADDR"]

2 、但是网上很多教程说上面的姿势不完善,还要解锁一下 36 式全方位姿势:

$user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
$user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];

3 、甚至还有 360 式的更全面的姿势:

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;
}

那么究竟应该用哪种呢?我们先来看下 REMOTE_ADDR 、 HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 是什么。
REMOTE_ADDR 访客 IP ,如果使用代理访问则显示代理 IP
HTTP_X_FORWARDED_FOR 访客 IP ,如果不使用代理访问则为空
HTTP_CLIENT_IP 代理服务器 IP ,如果不使用代理访问则为空
注意 REMOTE_ADDR 是无法更改的,而 HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 是由客户端(一般指代理服务器)自行设定的。

那么我们应该根据不同的需求去使用上面的 IP :
一、投票系统防刷票
此时应该使用上面的方法 1 去获取客户 IP ,因为方法 2 和方法 3 获取到的 HTTP_X_FORWARDED_FOR 、 HTTP_CLIENT_IP 有可能是刷票者伪造的。
二、网站访问统计
此时应该使用方法 2 或者方法 3 获取客户 IP ,以便访客通过代理服务器访问网站时能获取到访客的真实 IP

最后要注意的是,存进数据库前别忘记过滤一下:

preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] )

13021 次点击
所在节点    PHP
37 条回复
Hello1995
2015-10-23 11:15:40 +08:00
@em2046 . 是任意匹配字符,\. 匹配特定字符”.“。
ango
2015-10-23 11:31:29 +08:00
@Vonex 在 [ ] 内具有特定匹配语义的字符时,该字符仅表示普通字符,一般不用加转义符 \ 的了,除了首位的 ^ 。
xylophone21
2015-10-23 11:53:43 +08:00
什么叫真实 ip ?这个定义不说清楚,讨论就没有意义了。

我在路由器后面,我的真实 ip 是不是 192.168.1.123?还是路由器 wan 的 ip ?
我跟 100 个人在同一个路由器后面,我们的真实 ip 都是路由器 wan 的 ip ?
Hipponensis
2015-10-23 12:30:12 +08:00
mark 学习
mornlight
2015-10-23 13:20:41 +08:00
走匿名代理的时候服务端理论上没法直接通过这几个值拿到用户真实 ip
ryd994
2015-10-23 13:43:47 +08:00
不用 cdn ,就只用 remote address
用 cdn 就只信任来自 cdn IP 段的 remote address
其他一律不必考虑
msg7086
2015-10-23 13:47:59 +08:00
@crazystory realip 可以做得比较透明,不用改后台程序,也可以过滤来源服务器。
crazystory
2015-10-23 15:15:12 +08:00
@msg7086 但是依然脱离不了自定义 head 。。。结果并没有啥改变
boro
2015-10-23 16:23:15 +08:00
此方法能否用来识别垃圾留言的真实 IP ?
v7
2015-10-23 18:01:07 +08:00
http 协议代理转发原理 推荐阅读<http 权威指南>
理论上 X-Forwarded-For 会存储途径 ip
但并不是 X-Frowarded-For 的第一个 ip 就是真实 IP 这里是复杂的
msg7086
2015-10-23 20:28:38 +08:00
@crazystory 你说的结果是什么东西?
jings
2015-10-23 23:42:15 +08:00
<?php
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
echo $ip;
}
?>
jings
2015-10-24 00:22:22 +08:00
上面说了那么多不如贴图
txlty
2015-10-24 01:46:26 +08:00
自己实现了一套相对复杂的逻辑。不是一个函数就搞定的。
REMOTE_ADDR 、 HTTP_X_FORWARDED_FOR 都要获取并储存(其他的不用获取,纯属多余)。然后有一个不断搜集、更新的 tor 出口节点列表。这些都用来配合判断是否是正常访客。
一旦判断为问题用户,就在数据库里打上标识。只可以正常浏览,但某些操作进行限制。

其实还可以做的更多。比如,某些机构、学校、内网宽带用户,里面有超过一万台上网设备,却只有一个出口 IP 。这就导致 投票限制、注册限制、批量操作限制 很不好处理。
可以搜集这些 IP ,对一些操作行为进行放宽。同时整理出学校内可信任的注册用户,加上标识。
一旦出现恶意用户,可以及时批量处理+限制操作,同时对信任的已登录用户放行。
有些学校、机构的出口 IP 会变化,这不要紧。获取、比对 学校内信任用户列表的最新 IP ,可以用来辅助更新对应学校的出口 IP 数据。
。。。。。。。
当然这些我没去做。现在逻辑已经很乱了。再去实现这些会崩溃的。
txlty
2015-10-24 02:00:53 +08:00
一般情况下,除了对 REMOTE_ADDR 获取到的 IP 正常的逻辑限制,还有:
1.限制 HTTP_X_FORWARDED_FOR 有数据的请求(一般来自网上搜集的免费 http 代理)
2.限制来自 tor 出口节点的请求。

做到这两点就够了。 0 成本获取大量 IP 的途径就这俩。

其他的,不管是来自 大量 web shell 、大量肉鸡、购买的匿名代理、各种 ss 、 vpn ,都是要产生经济成本的。如果有人不惜成本动用这些资源搞你,这根本限制不了。
至于免费的公共 ss 、 vpn 、 gae 。。。 IP 数量实在有限,算不上大量 IP 。归入正常逻辑限制就行,不用特殊处理。
evilic
2015-10-24 08:53:15 +08:00
匿名投票网站不要用 FORWARDED 的 IP ,那样你会发现你的服务器会因为被刷票而卡到死的。
wdlth
2015-10-24 09:05:46 +08:00
还有 True-CLient-IP 、 CF-Connecting-IP 等各种头……

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/230367

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX