在PHP中,获取用户的正确IP地址最准确的方法是什么?

9 浏览
0 Comments

在PHP中,获取用户的正确IP地址最准确的方法是什么?

有许多$_SERVER变量头可用于获取IP地址。我想知道是否有普遍共识,关于如何使用这些变量最准确地获取用户的真实IP地址(明白没有一种方法是完美的)?

我花了一些时间尝试找到一个深入的解决方案,并根据多个来源编写了以下代码。如果有人能够指出问题或提供更准确的方法,我会非常感激。

编辑包括来自@Alix的优化

 /**
  * 检索客户端实际IP地址的最佳猜测。
  * 考虑到由于不同ISP在跳跃之间处理标头中的IP地址的变化而导致的众多HTTP代理标头。
  */
 public function get_ip_address() {
  // 检查共享的互联网/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];
  // 检查通过代理传递的IP
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // 检查var中是否存在多个IP地址
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    foreach ($iplist as $ip) {
     if ($this->validate_ip($ip))
      return $ip;
    }
   }
  }
  if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
   return $_SERVER['HTTP_X_FORWARDED'];
  if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
   return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
  if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
   return $_SERVER['HTTP_FORWARDED_FOR'];
  if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
   return $_SERVER['HTTP_FORWARDED'];
  // 如果所有方法都失败,则返回不可靠的IP地址
  return $_SERVER['REMOTE_ADDR'];
 }
 /**
  * 确保一个IP地址既是有效的IP地址,也不在私有网络范围内。
  *
  * @access public
  * @param string $ip
  */
 public function validate_ip($ip) {
     if (filter_var($ip, FILTER_VALIDATE_IP, 
                         FILTER_FLAG_IPV4 | 
                         FILTER_FLAG_IPV6 |
                         FILTER_FLAG_NO_PRIV_RANGE | 
                         FILTER_FLAG_NO_RES_RANGE) === false)
         return false;
     self::$ip = $ip;
     return true;
 }

警告(更新)

REMOTE_ADDR仍然代表IP地址的最可靠来源。这里提到的其他$_SERVER变量可以被远程客户端轻易伪造。此解决方案的目的是尝试确定代理后面的客户端的IP地址。对于一般用途,您可以考虑将其与直接从$_SERVER['REMOTE_ADDR']返回的IP地址结合使用,并将两者都存储起来。

对于99.9%的用户,这个解决方案将完全满足您的需求。它无法防止0.1%的恶意用户通过注入自己的请求标头来滥用您的系统。如果依赖IP地址进行一些关键任务,请使用REMOTE_ADDR,不要费心迎合那些使用代理的用户。

0
0 Comments

问题的原因是在PHP中获取用户正确的IP地址时存在一些困难,因为$_SERVER变量中包含多个可能的IP地址信息。解决方法是根据常见的HTTP头信息中获取IP地址的优先级来编写代码,以确保返回的IP地址是正确的。

解决方法如下所示:

首先,检查$_SERVER['HTTP_CLIENT_IP']是否存在,如果存在,则返回该IP地址。

如果$_SERVER['HTTP_CLIENT_IP']不存在,则检查$_SERVER['HTTP_X_FORWARDED_FOR']是否存在。如果存在,则使用explode函数将该IP地址字符串按逗号分隔,并返回最后一个IP地址。

如果$_SERVER['HTTP_X_FORWARDED_FOR']也不存在,则返回$_SERVER['REMOTE_ADDR'],即本地主机地址。

此外,由于使用Squid时存在一些奇怪的问题,所以在处理$_SERVER['HTTP_X_FORWARDED_FOR']时需要使用explode函数。

以上代码和解决方法可以确保获取到用户的正确IP地址。

0
0 Comments

在PHP中获取用户正确的IP地址最准确的方法是使用REMOTE_ADDR变量。然而,即使这样,获取用户真实IP地址仍然不可靠。用户只需使用一个不管http_x_forwarded_forhttp_forwarded等头部的匿名代理服务器,你将只能获得代理服务器的IP地址。

你可以查看是否有一个匿名代理服务器IP地址的列表,但是无法确定这个列表是否100%准确,最多只能让你知道这是一个代理服务器。而且如果有人聪明地伪造HTTP转发的头部,你将无能为力。

假设我不喜欢当地的大学。我找出他们注册的IP地址,并通过做坏事的方式,使得你的网站禁止他们的IP地址,因为我发现你尊重HTTP转发。这个列表是无穷无尽的。

然后,还有内部IP地址,比如我之前提到的大学网络。很多使用的是10.x.x.x的格式。所以你只会知道它是转发给一个共享网络的。

然后我不会深入讨论,但动态IP地址是宽带的常态。所以,即使你获取到用户的IP地址,预计在2-3个月内,它也会发生变化,最长不会超过这个时间。

感谢你的建议。我目前正在使用用户的IP地址来帮助会话认证,通过使用他们的C类IP作为限制因素来限制会话劫持,但允许合理范围内的动态IP。伪造的IP地址和匿名代理服务器只是我必须为一小部分人解决的问题。

- 当然,对于这个目的来说,REMOTE_ADDR是正确的方法。任何依赖于HTTP头部的方法都容易被伪造。会话的持续时间有多长?动态IP地址不会快速改变。

它们确实会改变,特别是如果我想要改变它们(更改MAC地址,许多驱动程序都支持)。只使用REMOTE_ADDR足以获取它所连接到的最后一个服务器的IP地址。因此,在代理情况下,你会得到代理IP。

0
0 Comments

通过阅读以上内容,我们可以得出以下结论:

问题的出现原因是PHP中如何准确地获取用户的IP地址。

解决方法是使用给定的代码来获取IP地址。代码中使用了$_SERVER数组中的一些键来获取IP地址,例如HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR等。然后使用foreach循环和explode函数来处理可能存在的多个IP地址,然后使用filter_var函数对IP地址进行验证,确保其是一个有效的IP地址。

此外,还提到了一些优化和改进的建议,例如使用filter_var函数代替validate_ip函数来验证IP地址,简化HTTP_X_FORWARDED_FOR的代码等。还提到了一些关于安全性的问题和建议,以及一些特定情况下的解决方案,例如处理Cloudflare代理的情况。

最后,还提到了一些关于代码兼容性和错误的问题,以及对代码的使用和效果的评论。

通过阅读以上内容,我们可以了解到在PHP中获取用户的准确IP地址的最佳方法,并了解了一些相关的优化和安全性问题。

0