#php
Итак. Если например за 1 минуту с одного IP идёт 4 запроса, то мы блокируем доступ к сайту на 15 минут. Реализовать я это пытался на файлах, то есть записываем каждый раз в файл: ip|timestamp|0 Далее проверять, если последний timestamp меньше, чем 3 секунды, то добавлять ip|timestamp|1|ip|timestamp|2|ip|timestamp|3 и т.д. Если превысило 5, то блокируем доступ к сайту на 10 минут например. Но пришла в голову плохая мысль, ведь пользователей много в онлайне и файл заполнится до такой степени, что всему придёт конец. Сессии и cookie предлагать не стоит, так как запрос со стороннего сервера. Или вовсе моё мнение ошибочно?
Ответы
Ответ 1
А может не изобретать велосипед, а взять готовый и погнуть немного? Называется велосипед fail2ban.Ответ 2
Для nginx модуль LimitReq, который по дефолту включен при компиляциии. Для Apache не так просто, вопрос на SO. Предлагают mod_evasive и mod_cband, а также в общем случае mod_limitipconn, mod_bw, mod_bwshare.Ответ 3
Если вЕлик необходим, я тут набросал. Расходы времени и размеров можно сократить, организовав сам файл правильно. К примеру, переводить ip в бинарный вид: function ip2bin($ip) { $ip = explode('.', $ip); return chr($ip[0]).chr($ip[1]).chr($ip[2]).chr($ip[3]); } // и наоборот: function bin2ip($bin) { return ord($bin[0]).'.'.ord($bin[1]).'.'.ord($bin[2]).'.'.ord($bin[3]); } Тогда точно будешь уверен: данные об IP занимают 4 байта. В идеале и всю остальную инфу тоже нужно хранить так же. Но я для примера сделал так: // понадобится для нормирования чисел в «обычном виде»: function norm_len($s, $len = 11, $fill = '0') { if (strlen($s) >= $len) return $s; else { $fill = $fill[0]; return str_repeat($fill, $len - strlen($s)).$s; } } $f = fopen('iptest.bin', "w"); $counter = 0; // заполняем нашу базу случайными значениями: for ($counter = 0; $counter < 200000; $counter++) { // случайный IP: $ip = rand(0,255).'.'.rand(0,255).'.'.rand(0,255).'.'.rand(0,255); // просто, чтоб знать, какой IP найдется — для теста: $count = $counter+1; $timestamp = time(); // приводим к нужному виду: $ip = ip2bin($ip); //$ip = norm_len($ip, 4, ' '); // 4 байта; приводить не требуется $count = norm_len($count, 10, '0'); // 10 байт $timestamp = norm_len($timestamp, 11, '0'); // 11 байт // теперь мы уверены, что размер каждой записи составляет // 4 + 10 + 11 = 25 (байт) fwrite($f, $ip.$count.$timestamp, 25); } fclose($f); die('Filled. Last IP: '.bin2ip($ip)); Файлик заполнен. Пробуем искать: $f = fopen('iptest.bin', "r"); $current_ip = '146.115.156.250'; $ip = NULL; fseek($f, 0); echo 'Searching for "'. $current_ip .'"...'."\n"; $current_ip = ip2bin($current_ip); // приводим к бинарному виду $length = filesize('iptest.bin'); //while (!feof($f)) // не работает почему-то.. while (ftell($f) < $length) { $ip = fread($f, 4); if ($ip === $current_ip) { echo '+ ' . bin2ip($ip).' <- that`s it!'."\n"; $count = intval(fread($f, 10)); $timestamp = intval(fread($f, 11)); echo ' Timestamp: '. $timestamp .' ('. date('Y-m-d H:i:s', $timestamp) .')'."\n"; echo ' Count: '. $count ."\n"; //break; // не будем выходить при первом совпадении } else { //echo '- ' . bin2ip($ip) ."\n"; fseek($f, 21, SEEK_CUR); // всегда точно знаем, на сколько нужно сместиться } } fclose($f); Функцию norm_len нужно доделать еще для отрицательных чисел (ну или учитывать "00000-23464" уже при «распаковке»). Хранилище изобретено. Чтение файла достаточно быстрое, но все же будет сильно нагружать систему при большом количестве клиентов. Этот метод нужно использовать для выявления злоумышленника, после чего информацию о бане записывать в сессию, чтобы не гонять постоянно винт по этому файлу. Я еще подумаю, как сделать асинхронный поиск по файлу (к примеру, составлять список задач, и производить поиск не чаще 1 раза в 10 секунд, после чего сохранять вердикт всамопальнуюсессию). Это позволит снизить нагрузку при чтении, но может дать плохишу дополнительные 10 секунд. Осталось только придумать, какие данные там лучше всего хранить, чтобы выявлять плохишей. Мой личный вывод: лучше не трогать похапе и прибегнуть к использованию готовых, более продвинутых решений.Ответ 4
Imho вариант с базой данных гораздо лучше варианта с файлом. Когда 100 потоков начнут писать в файл, то могут возникать коллизии или блокировки на запись. Никаких группировок и сортировок при работе с файлом не удастся нормально сделать. Когда-нибудь файл вырастет до такой степени, что защита сама сайт и положит. Вообще, смысла "Защищаться от частых перезагрузок страницы" нет. Если пользователь хочет перезагружать - пусть перезагружает. Делайте кеширование, если так нужно. Другое дело - защищать свой контент от неопознанных ботов-воришек. Т.е. вы можете сделать такую штуку, чтобы поиграться. Но профита она не даст. Готовое решение уже советовали - fail2ban. Блокировки ip будут на уровне iptables, а не кода приложения. Блокировки на основе лог-файлов сервера.
Комментариев нет:
Отправить комментарий