Alireza Noori
Alireza Noori

Reputation: 15275

Limit number of page visits based on ip

I wanted to know how can I prevent a single ip address from using too much bandwidth and rapidly access my webpages. That is, checking the user's ip address (I think $_SERVER['REMOTE_ADDR']?), check for latest visit from this user, compute time difference and block rendering the page if the interval is short. Am I right? If so, how can I do it without consuming too much resource and/or time on the server? If there is a database approach, isn't it going cause too many locks?

Upvotes: 2

Views: 7156

Answers (3)

evgpisarchik
evgpisarchik

Reputation: 460

Apache mod_bandwidth allows to control certain IPs

i.e. BandWidth <domain|ip|all> <rate>

https://httpd.apache.org/docs/trunk/mod/mod_ratelimit.html

Upvotes: 4

Howard
Howard

Reputation: 3895

The best approach depends on who you're trying to block. If it's genuine users who are constantly refreshing the page, then (a) do you really want to block them - they're your users!?, and (b) You can use a session-based approach to avoid DB hits. If it's bots then you can't rely on sessions (because they may not be sending the session headers, or they may be currently but are malicious bots who will get around it).

If it is genuine users, then assuming you're OK with setting session cookies, you'll want something like this:

<?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();
?>

If it's bots then you'll probably implement a database-based solution with similar logic.

In fact the correct solution in both cases is probably a caching proxy server in front of your application server. This will reduce load on your main app server and mean you won't have to worry so much about situations like this.

Upvotes: 6

Korhan Ozturk
Korhan Ozturk

Reputation: 11320

Here is the flood detection code that uses Memcache. If the user exceeds 50 visits within a minute, he's blokcked for 300 seconds. Remote address is used to identify the client.

<?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) );
?>

Upvotes: 2

Related Questions