2012-01-29 2 views
2

Я хотел знать, как я могу предотвратить использование одного IP-адреса слишком большой пропускной способностью и быстрый доступ к моим веб-страницам. То есть, проверяя IP-адрес пользователя (я думаю, $_SERVER['REMOTE_ADDR']?), Проверьте последний визит этого пользователя, вычислите разницу во времени и отбросите страницу, если интервал короткий. Я прав? Если да, то как я могу это сделать, не потребляя слишком много ресурсов и/или времени на сервере? Если есть подход к базе данных, разве это не приведет к слишком большому количеству блокировок?Ограничение количества посещений страниц на основе ip

+4

Если один пользователь действительно хочет атаковать ваш сайт таким образом, простой IP-блок PHP не остановит их. Тем более, что запрос уже находится в PHP и все равно использует ресурсы. – animuson

+0

Ваш недостающий самый важный материал, это ваш сервер, например VPS, выделенный или у вас есть доступ к брандмауэру и/или вы можете apt-get пакеты? или просто управляемый общий хостинг –

+0

Сервер посвящен. –

ответ

4

Apache mod_bandwidth позволяет контролировать определенный IP-адрес

т.е. BandWidth <domain|ip|all> <rate>

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

+2

Ваше право, если запрос попадает на php, атакующий уже выиграл. –

+0

Мне нравится ограничивать клиент перед доступом к PHP, но я не хочу просто ограничивать пропускную способность, которую они используют. Предположим, что есть клиент, который реализован как простой многопоточный искатель, и он загружает все страницы моего сайта. Кто я могу это предотвратить? –

5

Лучший подход зависит от того, кто вы пытаетесь заблокировать. Если это настоящие пользователи, постоянно обновляющие страницу, то (а) вы действительно хотите их заблокировать - они ваши пользователи!? И (б) Вы можете использовать подход на основе сеанса, чтобы избежать ударов БД. Если это боты, то вы не можете полагаться на сеансы (потому что они могут не отправлять заголовки сеансов, или они могут быть в настоящее время, но являются вредоносными ботами, которые обойдутся).

Если это настоящие пользователи, то предполагается, что вы все в порядке с установкой куки сессии, вы хотите что-то вроде этого:

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

Если это ботами, то вы, вероятно, реализовать решение на основе базы данных с аналогичной логикой.

На самом деле правильным решением в обоих случаях является, вероятно, кеширующий прокси-сервер перед сервером приложений. Это уменьшит нагрузку на ваш основной сервер приложений и означает, что вам не придется так беспокоиться о таких ситуациях.

+0

Я хочу заблокировать * evil * пользователей/ботов, которые могут использовать всю пропускную способность моего сервера с помощью простого искателя. Как насчет накладных расходов на подход к базе данных? –

+0

Правильно, поэтому подход сеансов не будет работать. DB будет иметь некоторые накладные расходы, но вы, вероятно, попадаете в БД несколько раз за запрос в любом случае? Один дополнительный не будет иметь большого значения. Однако это будет уродливая таблица, и вам придется писать что-то, чтобы периодически очищать старых посетителей. Решение @eugene кажется мне лучше всего. – Howard

1

Вот код обнаружения наводнения, который использует 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)); 
?> 
Смежные вопросы