首页 文章

在PHP中检索用户正确IP地址的最准确方法是什么?

提问于
浏览
263

我知道有很多 $_SERVER 变量头可用于IP地址检索 . 我想知道如何使用所述变量最准确地检索用户的真实IP地址(很清楚没有方法是完美的)?

我花了一些时间试图找到一个深入的解决方案,并根据许多来源提出了以下代码 . 我会喜欢它,如果有人可以请求答案中的漏洞或对某些可能更准确的东西有所了解 .

edit includes optimizations from @Alix

/**
  * Retrieves the best guess of the client's actual IP address.
  * Takes into account numerous HTTP proxy headers due to variations
  * in how different ISPs handle IP addresses in headers between hops.
  */
 public function get_ip_address() {
  // Check for shared internet/ISP IP
  if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
   return $_SERVER['HTTP_CLIENT_IP'];

  // Check for IPs passing through proxies
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
   // Check if multiple IP addresses exist in var
    $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'];

  // Return unreliable IP address since all else failed
  return $_SERVER['REMOTE_ADDR'];
 }

 /**
  * Ensures an IP address is both a valid IP address and does not fall within
  * a private network range.
  *
  * @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地址结合使用 .

For 99.9% of users this solution will suit your needs perfectly. 它不会通过注入自己的请求标头来保护您免受0.1%的恶意用户的攻击 . 如果依赖IP地址来完成关键任务,请求 REMOTE_ADDR 并且不要为代理背后的人提供服务 .

16 回答

  • 0

    我想知道你是否应该以相反的顺序迭代爆炸的HTTP_X_FORWARDED_FOR,因为我的经验是用户的IP地址最终在逗号分隔列表的末尾,所以从头的开头开始,你是更有可能获得返回的其中一个代理的IP地址,这可能仍然允许会话劫持,因为许多用户可能通过该代理 .

  • 0

    Here is a shorter, cleaner way to get the IP address:

    function get_ip_address(){
        foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
            if (array_key_exists($key, $_SERVER) === true){
                foreach (explode(',', $_SERVER[$key]) as $ip){
                    $ip = trim($ip); // just to be safe
    
                    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                        return $ip;
                    }
                }
            }
        }
    }
    

    我希望它有所帮助!


    你的代码似乎已经非常完整,我看不到任何可能的错误(除了通常的IP警告),我会改变 validate_ip() 函数依赖于过滤器扩展:

    public function validate_ip($ip)
    {
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)
        {
            return false;
        }
    
        self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this
    
        return true;
    }
    

    您的 HTTP_X_FORWARDED_FOR 代码段也可以简化:

    // check for IPs passing through proxies
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
        // check if multiple ips exist in var
        if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)
        {
            $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    
            foreach ($iplist as $ip)
            {
                if ($this->validate_ip($ip))
                    return $ip;
            }
        }
    
        else
        {
            if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
                return $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
    }
    

    对此:

    // check for IPs passing through proxies
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
        $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    
        foreach ($iplist as $ip)
        {
            if ($this->validate_ip($ip))
                return $ip;
        }
    }
    

    您可能还需要验证IPv6地址 .

  • 0

    然而,即便如此,获取用户的真实IP地址也是不可靠的 . 他们所需要做的就是使用一个匿名代理服务器(一个不尊重http_x_forwarded_for,http_forwarded等标头的服务器),你得到的只是他们的代理服务器的IP地址 .

    然后,您可以查看是否存在匿名的代理服务器IP地址列表,但是无法确保100%准确,并且它所做的最多就是让您知道它是代理服务器 . 如果有人聪明,他们可以欺骗HTTP转发的标头 .

    假设我不喜欢当地的大学 . 我弄清楚他们注册了哪些IP地址,并通过做坏事来获取他们在您网站上禁用的IP地址,因为我发现您尊重HTTP转发 . 名单是无止境的 .

    然后,正如您所猜测的那样,内部IP地址,例如我之前提到过的大学网络 . 很多都使用10.x.x.x格式 . 所以你要知道的是,它被转发为共享网络 .

    然后我不会开始考虑它,但动态IP地址已经成为宽带的方式了 . 所以 . 即使您获得了用户IP地址,也希望它在2-3个月内更改,最长 .

  • -6

    我们用:

    /**
     * Get the customer's IP address.
     *
     * @return string
     */
    public function getIpAddress() {
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return $_SERVER['HTTP_CLIENT_IP'];
        } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            return trim($ips[count($ips) - 1]);
        } else {
            return $_SERVER['REMOTE_ADDR'];
        }
    }
    

    HTTP_X_FORWARDED_FOR的爆炸是因为我们在使用Squid时检测到IP地址的奇怪问题 .

  • 0

    最大的问题是出于什么目的?

    您的代码几乎尽可能全面 - 但我看到如果您发现看起来像代理添加 Headers 的内容,您可以使用CLIENT_IP的INSTEAD,但是如果您希望将此信息用于审计目的,则会发出警告 - 非常简单假的 .

    当然,你永远不应该使用IP地址进行任何形式的身份验证 - 即使这些也可能是欺骗性的 .

    你可以通过推出一个通过非http端口连接回服务器的flash或java applet来更好地测量客户端ip地址(因此会显示透明代理或代理注入的头部为假的情况 - 但是请记住,客户端只能通过Web代理进行连接或者传出端口被阻止,小程序将无法连接 .

    C .

  • 2

    只是VB.NET版本的答案:

    Private Function GetRequestIpAddress() As IPAddress
        Dim serverVariables = HttpContext.Current.Request.ServerVariables
        Dim headersKeysToCheck = {"HTTP_CLIENT_IP", _
                                  "HTTP_X_FORWARDED_FOR", _
                                  "HTTP_X_FORWARDED", _
                                  "HTTP_X_CLUSTER_CLIENT_IP", _
                                  "HTTP_FORWARDED_FOR", _
                                  "HTTP_FORWARDED", _
                                  "REMOTE_ADDR"}
        For Each thisHeaderKey In headersKeysToCheck
            Dim thisValue = serverVariables.Item(thisHeaderKey)
            If thisValue IsNot Nothing Then
                Dim validAddress As IPAddress = Nothing
                If IPAddress.TryParse(thisValue, validAddress) Then
                    Return validAddress
                End If
            End If
        Next
        Return Nothing
    End Function
    
  • 1

    我意识到上面有更好,更简洁的答案,这不是一个功能,也不是最优雅的脚本 . 在我们的例子中,我们需要在简单的交换机中输出可欺骗的x_forwarded_for和更可靠的remote_addr . 它需要允许空格注入其他函数if-none或if-singular(而不仅仅是返回预格式化的函数) . 它需要一个“开启或关闭”变量,每个开关定制标签用于平台设置 . 它还需要一种方法让$ ip动态,具体取决于请求,以便它采取forwarding_for的形式 .

    此外,我没有看到任何人地址isset()vs!empty() - 它可能为x_forwarded_for输入任何内容但仍然触发isset()真相导致空白var,一种解决方法是使用&&并将两者结合起来作为条件 . 请记住,您可以将“PWNED”这样的单词伪装为x_forwarded_for,因此如果输出受保护的内容或进入数据库,请确保对真正的ip语法进行消毒 .

    此外,您可以使用谷歌翻译测试if你需要一个多代理来查看x_forwarder_for中的数组 . 如果你想欺骗 Headers 进行测试,请查看Chrome Client Header Spoof扩展名 . 这将默认为在anon代理后面的标准remote_addr .

    我不知道remote_addr可能是空的任何情况,但它的后备以防万一 .

    // proxybuster - attempts to un-hide originating IP if [reverse]proxy provides methods to do so
      $enableProxyBust = true;
    
    if (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR'])) && (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) && (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
        $ip = end(array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']))));
        $ipProxy = $_SERVER['REMOTE_ADDR'];
        $ipProxy_label = ' behind proxy ';
    } elseif (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR']))) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $ipProxy = '';
        $ipProxy_label = ' no proxy ';
    } elseif (($enableProxyBust == false) && (isset($_SERVER['REMOTE_ADDR']))) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $ipProxy = '';
        $ipProxy_label = '';
    } else {
        $ip = '';
        $ipProxy = '';
        $ipProxy_label = '';
    }
    

    要使这些动态在下面的函数或查询/回显/视图中使用,例如对于日志或错误报告,请使用全局变量或只在所需的任何地方回显em而不需要大量其他条件或静态模式输出功能 .

    function fooNow() {
        global $ip, $ipProxy, $ipProxy_label;
        // begin this actions such as log, error, query, or report
    }
    

    谢谢你所有的好主意 . 如果这可能会更好,请让我知道,这些 Headers 仍然有点新:)

  • 1

    我想出了这个函数,它不仅仅返回IP地址,而是一个包含IP信息的数组 .

    // Example usage:
    $info = ip_info();
    if ( $info->proxy ) {
        echo 'Your IP is ' . $info->ip;
    } else {
        echo 'Your IP is ' . $info->ip . ' and your proxy is ' . $info->proxy_ip;
    }
    

    这是功能:

    /**
     * Retrieves the best guess of the client's actual IP address.
     * Takes into account numerous HTTP proxy headers due to variations
     * in how different ISPs handle IP addresses in headers between hops.
     *
     * @since 1.1.3
     *
     * @return object {
     *         IP Address details
     *
     *         string $ip The users IP address (might be spoofed, if $proxy is true)
     *         bool $proxy True, if a proxy was detected
     *         string $proxy_id The proxy-server IP address
     * }
     */
    function ip_info() {
        $result = (object) array(
            'ip' => $_SERVER['REMOTE_ADDR'],
            'proxy' => false,
            'proxy_ip' => '',
        );
    
        /*
         * This code tries to bypass a proxy and get the actual IP address of
         * the visitor behind the proxy.
         * Warning: These values might be spoofed!
         */
        $ip_fields = array(
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
        );
        foreach ( $ip_fields as $key ) {
            if ( array_key_exists( $key, $_SERVER ) === true ) {
                foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
                    $ip = trim( $ip );
    
                    if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
                        $forwarded = $ip;
                        break 2;
                    }
                }
            }
        }
    
        // If we found a different IP address then REMOTE_ADDR then it's a proxy!
        if ( $forwarded != $result->ip ) {
            $result->proxy = true;
            $result->proxy_ip = $result->ip;
            $result->ip = $forwarded;
        }
    
        return $result;
    }
    
  • 1

    我的答案基本上只是@ AlixAxel答案的完美,完全验证和完全打包的版本:

    <?php
    
    /* Get the 'best known' client IP. */
    
    if (!function_exists('getClientIP'))
        {
            function getClientIP()
                {
                    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) 
                        {
                            $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
                        };
    
                    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key)
                        {
                            if (array_key_exists($key, $_SERVER)) 
                                {
                                    foreach (explode(',', $_SERVER[$key]) as $ip)
                                        {
                                            $ip = trim($ip);
    
                                            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
                                                {
                                                    return $ip;
                                                };
                                        };
                                };
                        };
    
                    return false;
                };
        };
    
    $best_known_ip = getClientIP();
    
    if(!empty($best_known_ip))
        {
            $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip;
        }
    else
        {
            $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip = '';
        };
    
    ?>
    

    变化:

    • 它简化了函数名称(使用'camelCase'格式化样式) .

    • 它包括一个检查,以确保该函数尚未在代码的另一部分中声明 .

    • 它考虑了“CloudFlare”的兼容性 .

    • 它将多个“IP相关”变量名称初始化为'getClientIP'函数的返回值 .

    • 它确保如果函数没有返回有效的IP地址,则所有变量都设置为空字符串,而不是 null .

    • 这只是(45)行代码 .

  • 9

    谢谢你,非常有用 .

    如果代码在语法上是正确的,那将有所帮助 . 因为它有一个{太多了20行 . 我害怕意味着没有人真正试过这个 .

    我可能很疯狂,但在尝试了几个有效和无效的地址之后,唯一有效的validate_ip()版本就是:

    public function validate_ip($ip)
        {
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false)
                return false;
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) === false)
                return false;
            if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false)
                return false;
    
            return true;
        }
    
  • 5

    如果您使用CloudFlare缓存层服务,这是一个修改后的版本

    function getIP()
    {
        $fields = array('HTTP_X_FORWARDED_FOR',
                        'REMOTE_ADDR',
                        'HTTP_CF_CONNECTING_IP',
                        'HTTP_X_CLUSTER_CLIENT_IP');
    
        foreach($fields as $f)
        {
            $tries = $_SERVER[$f];
            if (empty($tries))
                continue;
            $tries = explode(',',$tries);
            foreach($tries as $try)
            {
                $r = filter_var($try,
                                FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 |
                                FILTER_FLAG_NO_PRIV_RANGE |
                                FILTER_FLAG_NO_RES_RANGE);
    
                if ($r !== false)
                {
                    return $try;
                }
            }
        }
        return false;
    }
    
  • 2

    另一种干净的方式:

    function validateIp($var_ip){
        $ip = trim($var_ip);
    
        return (!empty($ip) &&
                $ip != '::1' &&
                $ip != '127.0.0.1' &&
                filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
                ? $ip : false;
      }
    
      function getClientIp() {
        $ip = @$this->validateIp($_SERVER['HTTP_CLIENT_IP']) ?:
              @$this->validateIp($_SERVER['HTTP_X_FORWARDED_FOR']) ?:
              @$this->validateIp($_SERVER['HTTP_X_FORWARDED']) ?:
              @$this->validateIp($_SERVER['HTTP_FORWARDED_FOR']) ?:
              @$this->validateIp($_SERVER['HTTP_FORWARDED']) ?:
              @$this->validateIp($_SERVER['REMOTE_ADDR']) ?:
              'LOCAL OR UNKNOWN ACCESS';
    
        return $ip;
      }
    
  • 0

    来自Symfony的Request类https://github.com/symfony/symfony/blob/1bd125ec4a01220878b3dbc3ec3156b073996af9/src/Symfony/Component/HttpFoundation/Request.php

    const HEADER_FORWARDED = 'forwarded';
    const HEADER_CLIENT_IP = 'client_ip';
    const HEADER_CLIENT_HOST = 'client_host';
    const HEADER_CLIENT_PROTO = 'client_proto';
    const HEADER_CLIENT_PORT = 'client_port';
    
    /**
     * Names for headers that can be trusted when
     * using trusted proxies.
     *
     * The FORWARDED header is the standard as of rfc7239.
     *
     * The other headers are non-standard, but widely used
     * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
     */
    protected static $trustedHeaders = array(
        self::HEADER_FORWARDED => 'FORWARDED',
        self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
        self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
        self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
        self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
    );
    
    /**
     * Returns the client IP addresses.
     *
     * In the returned array the most trusted IP address is first, and the
     * least trusted one last. The "real" client IP address is the last one,
     * but this is also the least trusted one. Trusted proxies are stripped.
     *
     * Use this method carefully; you should use getClientIp() instead.
     *
     * @return array The client IP addresses
     *
     * @see getClientIp()
     */
    public function getClientIps()
    {
        $clientIps = array();
        $ip = $this->server->get('REMOTE_ADDR');
        if (!$this->isFromTrustedProxy()) {
            return array($ip);
        }
        if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
            $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
            preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
            $clientIps = $matches[3];
        } elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
            $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
        }
        $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
        $firstTrustedIp = null;
        foreach ($clientIps as $key => $clientIp) {
            // Remove port (unfortunately, it does happen)
            if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
                $clientIps[$key] = $clientIp = $match[1];
            }
            if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
                unset($clientIps[$key]);
            }
            if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
                unset($clientIps[$key]);
                // Fallback to this when the client IP falls into the range of trusted proxies
                if (null ===  $firstTrustedIp) {
                    $firstTrustedIp = $clientIp;
                }
            }
        }
        // Now the IP chain contains only untrusted proxies and the client IP
        return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
    }
    
  • -1

    正如之前有人所说,这里的关键是你想要存储用户的ips的原因 .

    我将从我工作的注册系统中给出一个例子,当然这个解决方案只是为了在我的搜索中频繁出现的旧讨论中做出贡献 .

    许多php注册库使用 ip 根据用户的ip来限制/锁定失败的尝试 . 考虑一下这个表:

    -- mysql
    DROP TABLE IF EXISTS `attempts`;
    CREATE TABLE `attempts` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `ip` varchar(39) NOT NULL, /*<<=====*/
      `expiredate` datetime NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     -- sqlite
    ...
    

    然后,当用户尝试进行登录或与密码重置等服务相关的任何事情时,会在开始时调用一个函数:

    public function isBlocked() {
          /*
           * used one of the above methods to capture user's ip!!!
           */
          $ip = $this->ip;
          // delete attempts from this ip with 'expiredate' in the past
          $this->deleteAttempts($ip, false);
          $query = $this->dbh->prepare("SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ?");
          $query->execute(array($ip));
          $attempts = $query->fetchColumn();
          if ($attempts < intval($this->token->get('attempts_before_verify'))) {
             return "allow";
          }
          if ($attempts < intval($this->token->get('attempts_before_ban'))) {
             return "captcha";
          }
          return "block";
       }
    

    比方说,例如, $this->token->get('attempts_before_ban') === 10 和2个用户使用相同的ips,就像之前的代码 where headers can be spoofed 中的情况一样,然后每次尝试5次 both are banned !即使最糟糕的是,如果所有来自同一个代理,那么只会记录前10个用户,其余的将被禁止!

    这里的关键是我们需要一个表 attempts 上的唯一索引,我们可以从以下组合中得到它:

    `ip` varchar(39) NOT NULL,
     `jwt_load varchar(100) NOT NULL
    

    其中 jwt_load 来自遵循json web token技术的http cookie,其中我们只存储 encrypted 有效负载, should 包含每个用户的任意/唯一值 . 当然应该将请求修改为: "SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ? AND jwt_load = ?" 并且该类也应该启动 private $jwt .

  • 0

    你几乎回答了自己的问题! :)

    function getRealIpAddr() {
        if(!empty($_SERVER['HTTP_CLIENT_IP']))   //Check IP address from shared Internet
        {
            $IPaddress = $_SERVER['HTTP_CLIENT_IP'];
        }
        elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //To check IP address is passed from the proxy
        {
            $IPaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        else
        {
            $IPaddress = $_SERVER['REMOTE_ADDR'];
        }
        return $IPaddress;
    }
    

    Source

  • 218
    /**
     * Sanitizes IPv4 address according to Ilia Alshanetsky's book
     * "php|architect?s Guide to PHP Security", chapter 2, page 67.
     *
     * @param string $ip An IPv4 address
     */
    public static function sanitizeIpAddress($ip = '')
    {
    if ($ip == '')
        {
        $rtnStr = '0.0.0.0';
        }
    else
        {
        $rtnStr = long2ip(ip2long($ip));
        }
    
    return $rtnStr;
    }
    
    //---------------------------------------------------
    
    /**
     * Returns the sanitized HTTP_X_FORWARDED_FOR server variable.
     *
     */
    public static function getXForwardedFor()
    {
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        {
        $rtnStr = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
    elseif (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']))
        {
        $rtnStr = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
        }
    elseif (getenv('HTTP_X_FORWARDED_FOR'))
        {
        $rtnStr = getenv('HTTP_X_FORWARDED_FOR');
        }
    else
        {
        $rtnStr = '';
        }
    
    // Sanitize IPv4 address (Ilia Alshanetsky):
    if ($rtnStr != '')
        {
        $rtnStr = explode(', ', $rtnStr);
        $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
        }
    
    return $rtnStr;
    }
    
    //---------------------------------------------------
    
    /**
     * Returns the sanitized REMOTE_ADDR server variable.
     *
     */
    public static function getRemoteAddr()
    {
    if (isset($_SERVER['REMOTE_ADDR']))
        {
        $rtnStr = $_SERVER['REMOTE_ADDR'];
        }
    elseif (isset($HTTP_SERVER_VARS['REMOTE_ADDR']))
        {
        $rtnStr = $HTTP_SERVER_VARS['REMOTE_ADDR'];
        }
    elseif (getenv('REMOTE_ADDR'))
        {
        $rtnStr = getenv('REMOTE_ADDR');
        }
    else
        {
        $rtnStr = '';
        }
    
    // Sanitize IPv4 address (Ilia Alshanetsky):
    if ($rtnStr != '')
        {
        $rtnStr = explode(', ', $rtnStr);
        $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
        }
    
    return $rtnStr;
    }
    
    //---------------------------------------------------
    
    /**
     * Returns the sanitized remote user and proxy IP addresses.
     *
     */
    public static function getIpAndProxy()
    {
    $xForwarded = self::getXForwardedFor();
    $remoteAddr = self::getRemoteAddr();
    
    if ($xForwarded != '')
        {
        $ip    = $xForwarded;
        $proxy = $remoteAddr;
        }
    else
        {
        $ip    = $remoteAddr;
        $proxy = '';
        }
    
    return array($ip, $proxy);
    }
    

相关问题