使用PHP通过代理获取IPAddress?

时间:2012-10-19 09:02:49

标签: php ip-address

我对许多AJAX调用运行安全检查,以查看我记录的请求是否有相同的IP。

我使用以下一组类函数来建立IP(可以通过负载均衡器来实现,因此是长时间的方法。

    private function IPMask_Match ($network, $ip) {
      $ip_arr = explode('/', $network);
      if (count($ip_arr) < 2) {
        $ip_arr = array($ip_arr[0], null);
      }
      $network_long = ip2long($ip_arr[0]);
      $x = ip2long($ip_arr[1]);
      $mask =  long2ip($x) == $ip_arr[1] ? $x : 0xffffffff << (32 - $ip_arr[1]);
      $ip_long = ip2long($ip);
      return ($ip_long & $mask) == ($network_long & $mask);
    }


    private function IPCheck_RFC1918 ($IP) {
      $PrivateIP = false;
      if (!$PrivateIP) {
        $PrivateIP = $this->IPMask_Match('127.0.0.0/8', $IP);
      }
      if (!$PrivateIP) {
        $PrivateIP = $this->IPMask_Match('10.0.0.0/8', $IP);
      }
      if (!$PrivateIP) {
        $PrivateIP = $this->IPMask_Match('172.16.0.0/12', $IP);
      }
      if (!$PrivateIP) {
        $PrivateIP = $this->IPMask_Match('192.168.0.0/16', $IP);
      }
      return $PrivateIP;
    }


    public function getIP () {
      $UsesProxy = (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_CLIENT_IP'])) ? true : false;
      if ($UsesProxy && !empty($_SERVER['HTTP_CLIENT_IP'])) {
        $UserIP = $_SERVER['HTTP_CLIENT_IP'];
      }
      elseif ($UsesProxy && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $UserIP = $_SERVER['HTTP_X_FORWARDED_FOR'];
        if (strstr($UserIP, ',')) {
          $UserIPArray = explode(',', $UserIP);
          foreach ($UserIPArray as $IPtoCheck) {
            if (!$this->IPCheck_RFC1918($IPtoCheck)) {
              $UserIP = $IPtoCheck;
              break;
            }
          }
          if ($UserIP == $_SERVER['HTTP_X_FORWARDED_FOR']) {
            $UserIP = $_SERVER['REMOTE_ADDR'];
          }
        }
      }
      else{
        $UserIP = $_SERVER['REMOTE_ADDR'];
      }
      return $UserIP;
    }

问题是因为通过代理操作的用户遇到了问题。任何人都可以说明为什么会这样吗?我已经使用基本的免费代理在线尝试和模拟,但它看起来并没有获得可变的IP或任何东西 - 所以我不确定为什么这会说这两个IP不匹配。

5 个答案:

答案 0 :(得分:2)

我将解释代理首先是什么,所以我们都在同一页面上。

什么是代理

代理通常是单个计算机,用户访问互联网,然后代理将结果发送回用户。当可能有数百甚至数千名其他人也在使用那台计算机时出现问题 - 他们都拥有相同的IP地址,但通常标题表明用户是通过代理。

我假设你的脚本(没有正确查看)会让IP和标题混淆。

不同解决方案

有一种更好的方法。使用会话并在会话中保存密钥,确保他们在访问ajax页面之前先访问过主站点。例如:

的index.php

session_start();
$_SESSION['ajax_ok'] = true;

AJAX / username_check.php

session_start();
if (empty($_SESSION['ajax_ok'])) {
    die("You can not access this page...");
}

这将强制他们必须首先访问您的主站点,并且客户端还必须支持大多数浏览器的会话,以帮助防止机器人滥用您的Ajax脚本。

比使用上面提到的那些代码&gt;&lt;

更可靠,更简单的解决方案

如果您无法使用会话该怎么办?

如果你不能在你所使用的特定组件上使用会话,你可以设置另一台计算机,重写会话处理程序(使用php提供的回调)或者不使用文件系统使用像数据库这样的其他东西对于会话而言?您的网站必须使用会话也可以使用的内容。例如,如果你有一个基于负载均衡器文件的会话通常不会工作,所以通常最好改变会话以使用像我上面提到的其他内容。

答案 1 :(得分:2)

遗憾的是,问题几乎肯定不是代理 - 它几乎可以肯定是固定的公共IP路由器,通过子网路由流量。

子网可能很大(比如在大学)。

即使是一些真正的代理人(他们现在很少见 - 10岁的技术),即使代理志愿者转发,它也不会发生任何意义,因为它几乎肯定是一个子网ip像192.168.xx一样..这基本上是公共IP地址(又称交换机)内部扩展。

你可以交叉手指尝试php ipv6 Working with IPv6 Addresses in PHP甚至更聪明,尝试使用mac地址How can I get the MAC and the IP address of a connected client in PHP?,但两者都注定要失败。我的直觉是试图欺骗:我会赌博,最好的方法是基本上使用网络共享的会话存储,并允许负载平衡的PHP服务器所有访问它,并通过相同的DNS前缀做一切。或者也许是为了进行会期聚会而设立第三方dns。

答案是,除非您像广告代理商一样使用“Cookie”进行跟踪,否则无法进行跟踪。

答案 2 :(得分:1)

一位朋友发现了这一点,基本上一些代理可以用X_FORWARDED_FOR作为逗号分隔值或以逗号分隔和间隔返回。

修复: -

后:

foreach ($UserIPArray as $IPtoCheck) {

添加以下行:

$IPtoCheck = trim($IPtoCheck);

排序。

答案 3 :(得分:0)

  

问题是我一直遇到通过用户操作的用户的问题   代理。任何人都可以说明为什么会这样吗?我已经使用了基本免费版   代理的在线尝试和模拟,但它似乎没有得到   可变IP或任何东西 - 所以我不确定为什么会这样说   这两个IP不匹配。

您的解析代码在逗号上展开HTTP_X_FORWARDED_FOR,但分隔符可能是“逗号空间”。如果发生这种情况,RFC 1918检查将失败。虽然某些代理不添加空间,但标准是使用它:

http://en.wikipedia.org/wiki/X-Forwarded-For
  

该字段的一般格式为:

X-Forwarded-For: client, proxy1, proxy2
     

其中值是逗号+空格分隔的IP地址列表,   最左边是原始客户端,每个连续代理都是   通过请求添加收到请求的IP地址   从。在此示例中,请求传递了proxy1,proxy2和proxy3   (proxy3显示为请求的远程地址)。

因此,您应该将explode分隔符更改为“,”或更好,将preg_split与“,\ s *”一起用作分隔符,并涵盖两种情况。

然后,您的问题是将在AJAX中调用的页面验证为AJAX调用本身。

如果您不想使用基于cookie的会话,这是最好的方法,您可以尝试使用 nonce 执行此操作。也就是说,当您生成页面时,您发出一个唯一的ID并将其注入HTML代码,其中AJAX代码将恢复它并传递回AJAX servlet。后者将能够在详细here中将其添加到Access-Control-Request中,或者只是向请求中添加更多数据。

答案 4 :(得分:0)

我想讨论一下您的解决方案是否代表安全做了什么。

$ _ SERVER ['REMOTE_ADDR']无法伪造。它由Web服务器设置,因为使用了访问的IP地址。任何回复都会转到这个地址。

$ _ SERVER ['HTTP_FORWARDED_FOR']和$ _SERVER ['HTTP_CLIENT_IP']可以很容易伪造,因为它们是发送到网络服务器的HTTP标头 - 如果它被配置为省略这些,你也不知道你正在与代理通话标题,如果客户决定插入这些标题,您也不会知道您不与代理通话。

根据IP地址进行过滤FORGED对你没有什么帮助,但这在很大程度上取决于你想要达到的目标 - 在你进一步详细介绍之前,这仍然是未知的。

如果您环顾四周,您将偶然发现用于PHP的Suhosin补丁和扩展,并且它的功能是加密会话和cookie内容。加密密钥是通过使用一些静态密钥构建的,但是添加了诸如HTTP用户代理或请求IP地址的部分之类的内容 - 注意:用于实际发出请求的IP,即使用的代理,因为这是只有可靠的信息。

有人可能会争辩说,使用完整的IP地址并不是一个好主意,除非您知道您的用户不使用代理群集来更改多个请求的IP地址,因此通常只会使用部分IP地址,或者没有一点都不。

HTTP用户代理虽然是一个很好的独特信息来源。是的,它可以伪造,但这根本不重要,因为如果您只想允许来自同一源的请求,则假定用户代理字符串不随时间变化是有效的,但对于一堆其他用户。因此,有统计数据显示,如果只查看发送的所有HTTP标头,您可以生成几乎唯一的浏览器指纹,因为每个用户都会安装不同的扩展名来更改内容,例如接受内容标题。

我无法提供工作代码,也无法从您的问题中判断出这个答案是否适用,但我建议不要使用IP信息,特别是如果它可以伪造的话。如果考虑IPv6,甚至在同一个接口上每个客户端都有多个活动地址,这甚至更有效,并且它们都是随机生成的,并且不太可能在以后再次发生。 (当然,如果您永远不会主持IPv6,这不适用,但在某些时候您将不再是用户。)