Недавно у меня был один IP-вызов одной и той же страницы 15 000 раз подряд, который израсходовал много ресурсов сервера (что привело к получению предупреждения от службы Host). Я нахожусь на общем хосте, поэтому не могу загрузить новые модули и, следовательно, не имею реальных возможностей действительно ограничить пропускную способность IP.
Итак, я пытаюсь выяснить, как я могу использовать наименьшее количество ресурсов для определения нарушающего IP-адреса и перенаправления его на страницу 403 Forbidden. Я уже проверяю обычные хаки и использую Project HoneyPot, но делать это для каждого из 15 000 обращений к страницам неэффективно (и, как этот, он не охватывает их всех).
В настоящее время я регистрирую доступ к каждой странице в таблицу MySQL под названием visitors
, Я могу представить несколько способов сделать это:
Вариант 1: использование MySql:
1) Запрос visitors
таблица количества обращений с IP за последние 10 секунд.
2) Если число больше определенного (15?), Отметьте последнюю запись в visitors
как заблокировано для этого IP.
3) С каждым последующим запросом страницы, запрос на visitors
Таблица покажет IP как заблокированный, и я могу затем перенаправить на страницу 403 Forbidden.
Вариант 2. Изменение файла включения на лету, который содержит IP-адреса из черного списка:
1) Include
файл, который возвращает массив IP-адресов из черного списка
2) Если текущего IP нет в списке, запросите visitors
Таблица, как в варианте 1, чтобы увидеть, больше ли количество обращений с IP за последние 10 секунд, чем определенное число.
3) Если IP нарушает, измените include
файл, чтобы включить этот IP-адрес, как показано ниже.
По сути, мой вопрос: который использует больше ресурсов (х 15 000): запрос к базе данных или код ниже, который использует include
прочитать файл и затем array_search (), ИЛИ есть ли лучший способ сделать это?
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$filename='__blacklist.php';
if (file_exists($filename)){
// get array of excluded ip addresses
$array = (include $filename);
// if current address is in list, send to 403 forbidden page
var_dump($array);
if (is_array($array) && array_search($ip, $array) !== false){
blockAccess("Stop Bugging Me!");
}
} else {
echo "$filename does not exist";
}
// evaluate some condition which if true will cause IP to be added to blacklist - this will be a query to a MySql table determining number of hits to the site over a period of time like the last 10 seconds.
if (TRUE){
blockip($ip);
}
// debug - let's see what is blocked
// $array = (include $filename);
// var_dump($array);
// add the ip to the blacklist
function blockip($ip){
$filename='__blacklist.php';
if (! file_exists($filename)){
// create the include file
$handle = fopen($filename, "w+");
// write beginning of file - 111.111.111.111 is a placeholder so all new ips can be added
fwrite($handle, '<?php return array("111.111.111.111"');
} else {
// let's block the current IP
$handle = fopen($filename, 'r+');
// Don't use filesize() on files that may be accessed and updated by parallel processes or threads
// (as the filesize() return value is maintained in a cache).
// use fseek & ftell instead
fseek($handle, 0 ,SEEK_END);
$filesize = ftell($handle);
if ($filesize > 20){
// remove ); from end of file so new ip can be added
ftruncate($handle, $filesize-2);
// go to end of file
fseek($handle, 0 ,SEEK_END);
} else {
// invalid file size - truncate file
$handle = fopen($filename, "w+");
// write beginning of file with a placeholder so a new ip can be added
fwrite($handle, '<?php return array("111.111.111.111"');
}
}
//add new ip and closing of array
fwrite($handle, "," . PHP_EOL . '"' . $ip . '");');fclose($handle);
}function blockAccess($message) {
header("HTTP/1.1 403 Forbidden");
echo "<!DOCTYPE html>\n<html>\n<head>\n<meta charset='UTF-8' />\n<title>403 Forbidden</title>\n</head>\n<body>\n" .
"<h1>Forbidden</h1><p>You don't have access to this page.</p>" .
"\n</body>\n</html>";
die();
}
?>
Здесь есть много моментов, на которые следует обратить внимание.
Это в основном сводится к серверу, на котором он размещен. Общий хостинг не известен хорошим IO, и вам придется это проверить. Это также зависит от того, сколько IP-адресов вы будете в черном списке.
В идеале вы не хотите, чтобы злоумышленники обращались к PHP, когда вы определили, что они вредоносные. Единственный реальный способ сделать это в совместно используемой среде на Apache — заблокировать их от htaccess. Не рекомендуется, но есть возможность изменить htaccess из PHP.
Order Deny,Allow
Deny from xxx.xxx.xxx.xxx
Когда я читаю ваш вопрос, меня беспокоит то, что вы, похоже, не понимаете проблему. Если вы получаете 15 000 обращений за промежуток времени в секундах, у вас не должно быть 15 000 подключений к базе данных, и все эти запросы не должны обрабатывать PHP. Вам нужно кэшировать эти запросы. Если это происходит, ваша система в корне ошибочна. Для одного пользователя в домашнем интернете физически не должно быть возможности резко увеличить использование ресурсов.
В вашей ситуации я предлагаю приобрести VPS или что-то еще, что позволит вам использовать обратный прокси-сервер и использовать гораздо больше кэширования / внесения в черный список / мониторинга ресурсов.
Других решений пока нет …