Как обнаружить и запретить атакующие ips с помощью php - PullRequest
3 голосов
/ 05 ноября 2011

У меня есть веб-хостинг, который не позволяет редактировать iptables. Время от времени у меня есть легкие (около 300 запросов / сек) DoS-атаки (обычно не распространяемые). Я решил написать PHP-скрипт, который будет блокировать эти ips. Сначала я попытался сохранить все запросы за последние 10 секунд в базе данных и искать неправильные адреса для каждого запроса. Но я быстро понял, что таким образом я должен сделать по крайней мере 1 запрос к базе данных для каждого запроса DoS, и это не хорошо. Затем я оптимизировал этот подход следующим образом:

Read 'deny.txt' with blocked ip's
If it contains request ip, then die()
--- at this point we have filtered out all known attacking ips ---
store requesting ip in database
clean all requests older than 10 secs
count requests from this ip, if it is greater than threshold, add it to 'deny.txt'

Таким образом, новый атакующий ip будет делать только Threshold запросы к базе данных, а затем блокируется.

Итак, вопрос в том, имеет ли этот подход оптимальную производительность? Есть ли лучший способ выполнить эту задачу?

Ответы [ 2 ]

3 голосов
/ 05 ноября 2011

Попробуйте использовать Memcache, поиск будет намного быстрее.

Вы можете использовать IP-адрес для ключа.Прочитайте значение.Если он не существует, инициализируйте его 0, если это число, увеличьте его.Затем запишите его обратно с TTL 1 секунды или 10 секунд, или любой другой период, который вы хотите.Если количество превышает пороговое значение, было много запросов в период TTL, и вы можете заблокировать IP.

Обновление: я только что рассчитал, что установка обновленного значения снова даст ему новый TTL по крайней мере на одну секунду, поэтому IP-адрес может быть заблокирован, если он будет запрашивать <threshold> запросов с непрерывными интервалами, составляющими чуть менее секунды ...
Я не думаю, что это делает этот ответ совершенно бесполезным, но об этом следует помнить, если вы хотите сделать буквальныйреализация того, что я описал.

Блокировка может выполняться постоянно (путем регистрации в базе данных) или на меньший период.Для этого вы также можете использовать MemCache, зарегистрировав маркер (например, «X») вместо счетчика и установив TTL на более длительный период.Сценарий счетчика должен проверить, не является ли значение для чтения 'X', иначе счетчик перезапишет блок.

Я бы выбрал для этого Memcache, даже если вы хотите, чтобы черный список оставался постоянным.Поиск (который вам нужно сделать для каждого запроса) выполняется намного быстрее.Вы можете сохранить черный список IP-адресов в базе данных и восстанавливать этот список периодически или, по крайней мере, после перезагрузки сервера.Таким образом, вы получаете постоянный черный список без дополнительных затрат на проверку базы данных при каждом запросе.

2 голосов
/ 22 ноября 2011

Вот мой код:

$ip = $_SERVER['REMOTE_ADDR'];

// Log ip
$query = "INSERT INTO Access (ip) VALUES ('$ip')";      
mysql_query($query) or HandleException("Error on logging ip access: " . mysql_error() . "; Query: " . $query);  

// Here should be database cleanup code

// Count requests
$query = "SELECT COUNT(*) FROM Access WHERE ip='$ip' AND time > SUBTIME(NOW(), '00:01:00')";        
$result = mysql_query($query) or HandleException("Error on getting ip access count: " . mysql_error() . "; Query: " . $query);  
$num = mysql_fetch_array($result);
$accesses = $num[0];

// Ban ip's that made more than 1000 requests in 1 minute
if($accesses > 1000)
{
    file_put_contents('.htaccess', 'deny from ' . $ip . "\r\n", FILE_APPEND | LOCK_EX);
}

и заглушка .htaccess:

order deny,allow
deny from 111.222.33.44
deny from 55.66.77.88
...