限制基于ip的页面访问次数

时间:2012-01-29 22:04:45

标签: php

我想知道如何防止单个IP地址使用过多带宽并快速访问我的网页。也就是说,检查用户的IP地址(我认为$_SERVER['REMOTE_ADDR']?),检查该用户的最新访问,计算时差并在间隔较短时阻止呈现页面。我对吗?如果是这样,如何在不消耗太多资源和/或服务器时间的情况下执行此操作?如果有数据库方法,是不是会导致锁定太多?

3 个答案:

答案 0 :(得分:5)

最好的方法取决于你想阻止的对象。如果它是不断更新页面的真正用户,那么(a)你真的想要阻止它们 - 它们是你的用户!?,和(b)你可以使用基于会话的方法来避免数据库命中。如果它是机器人,那么你不能依赖会话(因为它们可能不会发送会话标题,或者它们可能是当前但是是恶意机器人会绕过它)。

如果它是真正的用户,那么假设您可以设置会话cookie,那么您需要这样的内容:

<?php
$min_seconds_between_refreshes = 3;

session_start();

if(array_key_exists('last_access', $_SESSION) && time()-$min_seconds_between_refreshes <= $_SESSION['last_access']) {
  // The user has been here at least $min_seconds_between_refreshes seconds ago - block them
  exit('You are refreshing too quickly, please wait a few seconds and try again.');
}
// Record now as their last access time
$_SESSION['last_access'] = time();
?>

如果它是机器人,那么你可能会实现一个基于数据库的解决方案,具有类似的逻辑。

事实上,在这两种情况下,正确的解决方案可能是应用程序服务器前面的缓存代理服务器。这将减少主应用服务器的负载,并且意味着您不必担心这样的情况。

答案 1 :(得分:4)

Apache mod_bandwidth允许控制某些IP

即。 BandWidth <domain|ip|all> <rate>

http://mansurovs.com/tech/apache-bandwidth-throttling

答案 2 :(得分:2)

以下是使用Memcache的洪水检测代码。如果用户在一分钟内超过50次访问,他就会被打包300秒。远程地址用于标识客户端。

<?php 

$limit = 50; 
$seconds = 60;  
$block_for_seconds = 300;

$status = 'OK';

$memcache = new Memcache;
$memcache->connect('localhost', 11211);

$ip = $_SERVER['REMOTE_ADDR'];

$r = $memcache->get($ip, array('c', 't'));

$c = 1; // count
$init_time = time();
if($r) {
  $s = $r[3]; // status
  $c = $r[0]+1;
  $init_time = $r[1];
  if($s == 'TOO_MANY_REQUESTS') {
    $d = time()-$r[1]; // time since block
    if($block_for_seconds-$d > 0) {  // still blocked
      die('Flood detected!! You are going to wait '.($block_for_seconds-$d).' and try again.');
    } else {  // block is over
      $status = 'OK';
      $init_time = time();
      $c = 0;
    }
  }

  $new_time = time();
  if($c > $limit) {  // check if happened within a minute
    $time_elapsed = $new_time - $init_time;
    if($time_elapsed < $seconds) {  
      $status = 'TOO_MANY_REQUESTS'; 
    }
    print "time elapsed: $time_elapsed, count:$c";
    $c = 0;
    $init_time = time();
  }
}
print_r($r);
$memcache->set($ip, array($c, $init_time, $new_time, $status) );
?>