Доброго дня! В статье расскажу как можно пользователям обычного хостинга отловить IP адреса генерирующие излишнюю нагрузку на сайт и затем блокировать их при помощи средств хостинга, будет «чуть-чуть» php кода, несколько скриншотов.

Вводные данные:

  1. Сайт созданный на CMS WordPress
  2. Хостинг Бегет (это не реклама, но скрины админки будут именно этого хостинг провайдера)
  3. WordPress сайт запущен где то в начале 2000 и имеет большое количество статей и материалов
  4. Версия PHP 7.2
  5. WP имеет последнюю версию
  6. С некоторых пор сайт начал генерировать высокую нагрузку на MySQL по данным хостинга. Каждый день это значение превышало 120% от нормы на учётную запись
  7. По данным Яндекс. Метрика сайт посещает 100-200 человек в сутки

В первую очередь было сделано:

  1. Очищены таблицы БД от накопившегося мусора
  2. Отключены не нужные плагины, убраны участки устаревшего кода

При этом обращаю внимание, пробовались варианты кеширования(плагины кеширования), проводились наблюдения — но нагрузка в 120% от одного сайта была неизменна и могла только расти.

То как выглядела примерная нагрузка по базам данных хостинга


В топе находится сайт о котором идёт речь, чуть ниже другие сайты которые имеют ту же cms и примерно такую же посещаемость, но создают меньше нагрузки.

Анализ

  • Было предпринято много попыток с вариантами кеширования данных, проводились наблюдения в течении нескольких недель (благо хостинг за это время мне ни разу не написал что я такой плохой и меня отключат)
  • Был анализ и поиск медленных запросов, затем была немного изменена структура БД и тип таблиц
  • Для анализа в первую очередь использовался встроенный AWStats (он кстати помог вычислить самый злой IP адрес по объему трафика
  • Метрика — метрика даёт информацию только о людях, а не о ботах
  • Были попытки использовать плагины для WP, которые умеют фильтровать и блокировать посетителей даже по стране нахождения и по различным комбинациям
  • Совсем радикальный способ оказался закрыть сайт на сутки с пометкой «Мы на техническом обслуживании» — это было так же сделано при помощи знаменитого плагина. В этом случае нагрузка ожидаем упала, но не до 0-левых значений, так как идеология WP базируется на хуках и плагины начинают свою активность при наступлении какого — либо «хука», а до наступления «хука» могут быть уже сделаны запросы к БД

Идея

  1. Вычислить IP адреса которые делают много запросов за короткий промежуток времени.
  2. Зафиксировать количество обращений к сайту
  3. На основе количества обращений блокировать доступ к сайту
  4. Блокировать при помощи записи «Deny from» в файле .htaccess
  5. Другие варианты, вроде iptables и правил для Nginx не рассматривая, ибо пишу про хостинг

Появилась идея, значит надо реализовывать, как без этого…

  • Создаём таблицы для накопления данных

    CREATE TABLE `wp_visiters_bot` (
    	`id` INT(11) NOT NULL AUTO_INCREMENT,
    	`ip` VARCHAR(300) NULL DEFAULT NULL,
    	`browser` VARCHAR(500) NULL DEFAULT NULL,
    	`cnt` INT(11) NULL DEFAULT NULL,
    	`request` TEXT NULL,
    	`input` TEXT NULL,
    	`data_update` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    	PRIMARY KEY (`id`),
    	UNIQUE INDEX `ip` (`ip`)
    )
    COMMENT='Кандидаты для блокировки'
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=1;
    

    CREATE TABLE `wp_visiters_bot_blocked` (
    	`id` INT(11) NOT NULL AUTO_INCREMENT,
    	`ip` VARCHAR(300) NOT NULL,
    	`data_update` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    	PRIMARY KEY (`id`),
    	UNIQUE INDEX `ip` (`ip`)
    )
    COMMENT='Список уже заблокированных'
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=59;
    

    CREATE TABLE `wp_visiters_bot_history` (
    	`id` INT(11) NOT NULL AUTO_INCREMENT,
    	`ip` VARCHAR(300) NULL DEFAULT NULL,
    	`browser` VARCHAR(500) NULL DEFAULT NULL,
    	`cnt` INT(11) NULL DEFAULT NULL,
    	`data_update` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    	`data_add` DATETIME NULL DEFAULT CURRENT_TIMESTAMP,
    	PRIMARY KEY (`id`),
    	UNIQUE INDEX `ip` (`ip`)
    )
    COMMENT='История всех запросов для дебага'
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=1;
    
  • Создадим файл в который поместим код. Код будет запись в таблицы кандидатов на блокировку и вести историю для дебага.

    Код файла, для записи IP адресов
    <?php
    
    if (!defined('ABSPATH')) {
        return;
    }
    
    global $wpdb;
    
    /**
     * Вернёт конкретный IP адрес посетителя
     * @return boolean
     */
    function coderun_get_user_ip() {
    
        $client_ip = '';
    
        $address_headers = array(
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
        );
    
        foreach ($address_headers as $header) {
            if (array_key_exists($header, $_SERVER)) {
    
                $address_chain = explode(',', $_SERVER[$header]);
                $client_ip = trim($address_chain[0]);
    
                break;
            }
        }
    
        if (!$client_ip) {
            return '';
        }
    
    
        if ('0.0.0.0' === $client_ip || '::' === $client_ip || $client_ip == 'unknown') {
            return '';
        }
    
        return $client_ip;
    }
    
    $ip = esc_sql(coderun_get_user_ip()); // IP адрес посетителя
    
    if (empty($ip)) {// Нет IP, ну и идите лесом...
        header('Content-type: application/json;');
        die('Big big bolt....');
    }
    
    $browser = esc_sql($_SERVER['HTTP_USER_AGENT']); //Данные для анализа браузера
    
    $request = esc_sql(wp_json_encode($_REQUEST)); //Последний запрос который был к сайту
    
    $input = esc_sql(file_get_contents('php://input')); //Тело запроса, если было
    
    $cnt = 1;
    
    //Запрос в основную таблицу с временными кондидатами на блокировку
    $query = <<<EOT
        INSERT INTO wp_visiters_bot (`ip`,`browser`,`cnt`,`request`,`input`)
            VALUES  ('{$ip}','{$browser}','{$cnt}','{$request}','$input')
             ON DUPLICATE KEY UPDATE cnt=cnt+1,request=VALUES(request),input=VALUES(input),browser=VALUES(browser)
    EOT;
    
    //Запрос для истории
    $query2 = <<<EOT
        INSERT INTO wp_visiters_bot_history (`ip`,`browser`,`cnt`)
            VALUES  ('{$ip}','{$browser}','{$cnt}')
             ON DUPLICATE KEY UPDATE cnt=cnt+1,browser=VALUES(browser)
    EOT;
    
    
    $wpdb->query($query);
    
    $wpdb->query($query2);
    
    


    Суть кода в том что бы получить IP адрес посетителя и записать его в таблицу. Если ip уже есть в таблице, будет произведено увеличение поля cnt (количество запросов к сайту)
  • Теперь страшное… Сейчас меня сожгут за мои действиия :)
    Что бы записывать каждое обращение сайту, подключаем код файла в главный файл WordPress — wp-load.php. Да именно изменяем файл ядра и именно после того как уже существует глобальная переменная $wpdb

Итак, теперь мы можем видеть как часто тот или иной IP адрес отмечается у нас в таблице и с кружкой кофе заглядываем туда раз в 5-ь минут для понимания картины



Дальше просто, скопировали «вредный» IP, открыли файл .htaccess и добавили в конец файла

Order allow,deny
Allow from all
# start_auto_deny_list
Deny from 94.242.55.248
# end_auto_deny_list

Всё, теперь 94.242.55.248 — не имеет доступа к сайту и не генерирует нагрузку на БД

Но каждый раз так руками копировать не очень праведное занятие, да и к тому же код задумывался как автономный

Добавим файл, который будет исполняться по CRON каждые 30 минут:

Код файла модифицирующий .htaccess
<?php

/**
 * Файл автоматического задания блокировок по IP адресу
 * Должен запрашиваться через CRON
 */
if (empty($_REQUEST['key'])) {
    die('Hello');
}

require('wp-load.php');

global $wpdb;

$limit_cnt = 70; //Лимит запросов по которым отбирать

$deny_table = $wpdb->get_results("SELECT * FROM wp_visiters_bot WHERE cnt>{$limit_cnt}");

$new_blocked = [];

$exclude_ip = [
    '87.236.16.70'//адрес хостинга
];

foreach ($deny_table as $result) {

    if (in_array($result->ip, $exclude_ip)) {
        continue;
    }

    $wpdb->insert('wp_visiters_bot_blocked', ['ip' => $result->ip], ['%s']);
}

$deny_table_blocked = $wpdb->get_results("SELECT * FROM wp_visiters_bot_blocked");

foreach ($deny_table_blocked as $blocked) {
    $new_blocked[] = $blocked->ip;
}

//Очистка таблицы
$wpdb->query("DELETE FROM wp_visiters_bot");

//echo '<pre>';print_r($new_blocked);echo '</pre>';

$file = '.htaccess';

$start_searche_tag = 'start_auto_deny_list';

$end_searche_tag = 'end_auto_deny_list';

$handle = @fopen($file, "r");
if ($handle) {

    $replace_string = '';//Тест для вставки в файл .htaccess

    $target_content = false; //Флаг нужного нам участка кода

    while (($buffer = fgets($handle, 4096)) !== false) {

        if (stripos($buffer, 'start_auto_deny_list') !== false) {
            $target_content = true;
            continue;
        }

        if (stripos($buffer, 'end_auto_deny_list') !== false) {
            $target_content = false;

            continue;
        }

        if ($target_content) {
            $replace_string .= $buffer;
        }
    }
    if (!feof($handle)) {
        echo "Ошибка: fgets() неожиданно потерпел неудачу\n";
    }
    fclose($handle);
}

//Текущий файл .htaccess
$content = file_get_contents($file);

$content = str_replace($replace_string, '', $content);

//Очищаем все блокировки в файле .htaccess
file_put_contents($file, $content);

//Запись новых блокировок
$str = "# {$start_searche_tag}" . PHP_EOL;

foreach ($new_blocked as $key => $value) {
    $str .= "Deny from {$value}" . PHP_EOL;
}

file_put_contents($file, str_replace("# {$start_searche_tag}", $str, file_get_contents($file)));


Код файла достаточно прост и примитивен и главная его идея в том что бы взять кандидатов на блокировку и вписать правила блокирвоки в файл .htaccess между комментариями
# start_auto_deny_list и # end_auto_deny_list

Теперь «вредные» ip блокируются сами собой, а файл .htaccess выглядит примерно так:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

Order allow,deny
Allow from all

# start_auto_deny_list
Deny from 94.242.55.248
Deny from 207.46.13.122
Deny from 66.249.64.164
Deny from 54.209.162.70
Deny from 40.77.167.86
Deny from 54.146.43.69
Deny from 207.46.13.168
....... ниже другие адреса
# end_auto_deny_list

В итоге после начала действия такого кода можно увидеть результат в хостинг панели:



PS: Материал авторский, хоть его часть я и публиковал на своём сайте но на Habre получилась более расширенная версия.

Комментарии (37)


  1. barbos6
    25.10.2019 11:52

    Идея
    Вычислить IP адреса которые делают много запросов за короткий промежуток времени.
    Зафиксировать количество обращений к сайту
    На основе количества обращений блокировать доступ к сайту


    Ну и получить падение реальной посещаемости, так как через этот IP, возможно, NATится сетка крупного провайдера или корпорации, либо это ip адрес VPN сервера или узла TOR.

    Ну прям по граблям РКН. :)


    1. northmule Автор
      25.10.2019 11:56

      Для крупных порталов, да — это возможно. Но в статье я рассматривал небольшой ресурс провинциального масштаба.
      Так же всегда есть возможность самостоятельно проверить IP (кто, от куда) и скорректировать правило.
      Или пойти дальше и блокировать таких «ботов» на определённое время
      Ещё извращённей вариант, это показывать заглушку до основного роута cms с предложеним ввести капчу :)


      1. asakasinsky
        25.10.2019 13:31
        +1

        Вдруг пригодится.
        Ограничение скорости обработки запросов в nginx
        Вкратце: с помощью nginx можно настроить ограничить скорость с предусмотрением всплесков.


        1. northmule Автор
          25.10.2019 13:33

          Благодарю, отличный вариант!


  1. webviktor
    25.10.2019 12:03

    Какие только велосипеды не придумают, чтоб fail2ban не использовать.


    1. Andy_Big
      25.10.2019 12:22

      Речь же про виртуальный хостинг, а не про выделенный :)


    1. darken99
      25.10.2019 12:35

      У вас ошибка в слове Cloudflare


    1. apapacy
      25.10.2019 15:08
      +1

      fail2ban сейчас практически не защищает от атак. Если устанавливать лимиты в nginx можно по крайней мере отделить запросы на приложение от простых запросов статики. А fail2ban все считает равноценными. Для него запрос 1 к php и 99 к статике равноценны 100 запросам к php. И получается что установив например те же 100 запросов в секунду как лимит мы можеи забанить нормального клиента который сделал 1 запрос к php и 99 запросов к статике и в то же время пропускать бота который будет делать атаку по 99 запросов в секунду к php


  1. eumorozov
    25.10.2019 12:40

    Вообще, это не самый эффективный метод, потому что он:


    1. Реактивный (то есть мы сначала получаем проблемы, а потом исправляем их)
    2. Не решает настоящую проблему (видимо сайт совсем медленный)

    Правильнее использовать наверное какой-нибудь throttling (например, на уровне nginx), нежели вручную отслеживать и добавлять каждый ip адрес.


    1. DaemonGloom
      25.10.2019 12:55
      +1

      2. Здесь проблема не в скорости обычно, а в цене хостинга. При покупке выдаётся определённое процессорное время, которое за этот период можно использовать. И такая лишняя нагрузка просто бессмысленно увеличивает цену, пользователи от подобного обычно не страдают (сам сайт не становится заметно медленнее). Но да, обычно такие проблемы решают или на уровне системных приложений (fail2ban, урезание лишних запросов через nginx и т.д.), или на уровне самой cms — временно блокировать пользователей по количеству хитов в минуту, разделяя при этом их по кукам, чтобы не резать людей за nat'ом.


      1. northmule Автор
        25.10.2019 13:12

        У nginx в этом плане много гибкости. На сайте одного крупного вендора продуктов здорового питания используется блокировка от атак именно на на основе nginx. Достаточно быстрое решение, но в случае крупного вендора — свой сервер.


    1. northmule Автор
      25.10.2019 13:16

      Сайт сам по себе, я бы сказал, достаточно быстрый, возможно не оптимален с точки зрения большого количества запросов к бд. Но видимо то что этот сайт достаточно старый его пытаются парсить все кому не лень или он по историческим просчётам попал в какие либо базы агрегаторов контента.
      Сам сайт носит СМИ направленность для провинциального города.


  1. corochoone
    25.10.2019 13:08

    А не проще было взять лог веб-сервера и его распарсить? Лог веб-сервера у подавляющего большинства хостеров доступен клиентам.


    1. northmule Автор
      25.10.2019 13:09

      С парсингом лог файла, тоже отличная идея. Но у хостеров это подключаемая опция, т.е ведение лога начинается после активации этой опции.
      Ну и запись в БД «живых запросов» мне показалась более быстрой с точки зрения реализации


  1. Tetragonchik
    25.10.2019 13:08

    Я в детстве так думал: если, например у меня болел палец — почему бы взять его и не отрезать? Пусть себе болит на здоровье, зато у меня ничего болеть не будет :)


    1. northmule Автор
      25.10.2019 13:17

      Я честно говоря, ваш тонкий юмор не уловил


      1. me-zundig
        25.10.2019 13:56

        Это тонкий намек, на Ваши предпринятые меры. Нарастили функционал, а проблема на самом деле пока может быть схлопнулась, но не ушла. С такими кейсами лучше бороться по другому.


        1. northmule Автор
          25.10.2019 13:57

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

          Я не утверждаю что опубликованное мной решение — хорошее, это всего лишь вариант.


          1. me-zundig
            25.10.2019 14:12

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


          1. me-zundig
            25.10.2019 14:14

            А вообще — мой вам совет мигрировать в сторону впс, это сейчас дешево, но зато вы откроете новый чудесный мир :)


            1. northmule Автор
              25.10.2019 14:19

              впс — это свобода, но в процентном отношении это на 50% дороже того что используется сейчас (т.е экономически получится не обоснованно), но при этом ещё возможны варианты оптимизации что бы удержаться в рамках тарифа.

              В качестве мидлвар можно сделать связку с redis или memcached, но это уже другая история и пожалуй другая статья, хотя и возможна на приведённом в статье хостинг провайдере.


              1. me-zundig
                25.10.2019 14:33

                вполне приличный впс сейчас можно купить в РФ за 100-200 руб в месяц, думаю 50% тут смогут нивелироваться?


                1. northmule Автор
                  25.10.2019 14:36

                  Можно, но с какими характеристиками? Или дайте ссылку на железно-проверенный сервис


                  1. me-zundig
                    25.10.2019 14:44
                    +1

                    Дам ссылку заминусуют :) но если без ссылок, например айхор. Еще как фича, Вы можете все хостить на домашнем железе, например, передав все редиректы в cdn cloudflare, от вас нужен только реальный ip и немного телодвижений, как бонус клодфлэр еще организуют валидный https.


                    1. me-zundig
                      25.10.2019 14:46

                      и кстати, какой-то паразитный трафик отфильтрует бесплатно :)

                      www.cloudflare.com


  1. Tetragonchik
    25.10.2019 14:14

    Ну я не очень то понял, почему конкретно тормозит база. Запросы каких страниц с предполагаемых спамных IP вызывали тормоза? Как вы поняли что это боты? Какие запросы с этих страниц к БД вызвали перегруз? Почему не помогли кэшировщики? Что в логах? Числятся ли эти айпишники в спам-базах? Мне показалось, что вы не выявили до конца проблему и просто отрезали проблемное место. Очень возможно, что вместе с потенциальными посетителями. Вместе с последней картинкой просто просится график посещаемости сайта :) Ну для спокойствия, что вы все правильно сделали.


    1. northmule Автор
      25.10.2019 14:32

      Отвечу на некоторые из Ваших вопросов, они особо актуальны и думаю при ответе на них частично отвечу на другие:

      Числятся ли эти айпишники в спам-базах

      Да, с этих IP приходит спам в комментарии к постам, об этом так же сообщает сервис Akismet.
      Вместе с последней картинкой просто просится график посещаемости сайта :)

      Суммарно он не изменился, по данным Яндекс Метрики
      Ну я не очень то понял, почему конкретно тормозит база

      Тормозит совсем не база, а у хостинга есть абстрактная величина «CP» — которая имеет разумные рамки и при превышении рамок сообщает «Эй, клиент, у тебя превышен отведённый тебе лимит нагрузки на центральный процессор, сделай что нибудь, а то мы выключим сайт». Да, конечно нужно уменьшить количество запросов к БД генерируемых 1-й страницей сайта, но требовалось именно потушить пожар (снизить нагрузку, что бы не получить санкции). Пожар потушен, можно проводить анализ.
      Как вы поняли что это боты?

      • По заголовкам браузера
      • По запросам POST и GET. Например бот «прозванивает» роуты сайта на наличие тех или иных плагинов которые видимо имеют уязвимость(но этих плагинов у меня нет)


  1. Tetragonchik
    25.10.2019 14:42

    Благодарю за ответы. Подскажите, если не сложно, как быстро растет .htaccess? Сколько времени прошло с момента запуска скрипта и сколько там уже заблоченных адресов?


    1. northmule Автор
      25.10.2019 14:52

      Полноценно скрипт был запущен несколько дней назад, т.е работает меньше недели. Сейчас в .htaccess всего около 30 адресов. При этом большая часть была добавлена туда в первые дни работы скрипта. Например вчера в чёрный список попал всего 1-н адрес, та как в районе 5-и утра по МСК — генерировал просто огромное количество запросов за 30-и минутный интервал.


    1. me-zundig
      25.10.2019 14:55

      наращивать тетрадными строками в .htaccess это ужас и боль, нужно оперировать сетевыми битными масками в мидлварщине, которая принимает решение дропать в блекхол или дать на обслуживание


  1. apapacy
    25.10.2019 15:01
    +1

    Была пара статей на Хабре например https://habr.com/ru/post/354744/ и в ней ссылка на еще одну статью как определять ботов. Простых ботов можно определить по способности сетать куки и делать редиректы. Конечно, продвинутые боты это обойдут. Но продвинутые боты никогда и не стучатся с одного адреса. То есть от серьезной атаки не спасет ни один из этих методов.


    1. tuxi
      26.10.2019 00:35

      Они все равно поведенческими алгоритмами вычисляются достаточно адекватно (при стабильном трафике живых людей). К тому же, половина из них и не скрывается, семраш тот же самый.
      Универсальной защиты конечно нет. Но есть успешные примеры кастомных решений под свои нужды, исходя из особенностей конкретного проекта. Основной вопрос тут: а какая итоговая цель?


  1. tuxi
    26.10.2019 00:26

    1) у nginx есть зеркалирование реквестов, зовется /mirror. Вот и отправляйте туда данные, обрабатывайте на чем угодно, оттуда пишите в свою БД или еще куда-нибудь

    2) отбиваться от ботов (на первом этапе этого непростого пути) надо хотя бы через резолвинг айпи в имя, а еще лучше через rest.db.ripe.net/search. Получаете ответ, парсите его и понимаете с хорошей долей вероятности, «кто же это такой красивый к вам пришел».
    Как минимум, более менее честный белый список поисковых ботов составите. Уже не навредите своим позициям в поисковых системах.


  1. dady_KK
    26.10.2019 22:13
    +1

    Прочитал статью, поплевался на код, вспомнил, что это шаред хостинг и вордпресс и вот что хочется сказать: решение вполне жизнеспособное, сыроватое, но когда тебя парсят или пытаются школьники задедосить и нужно что-то на быструю руку, то вариант вполне. Теперь немного по критике способа. Мы используем похожую систему, но сильно модифицированную, но начинали примерно с такой же, поэтому есть что сказать и автору и критикам.


    Тем, кто думает, что блокировка айпи может как-то повлиять на посещаемость, то вынужден разочаровать — нат, впн, прокси, мобильные айпи — это редкие единичные случаи, которыми можно пренебречь. Кроме того, можно сделать и временную блокировку (и лучше так и делать) и кроме этого можно для таких айпи и каптчу спрашивать (в том числе и рекаптчу3 или вторую в невидимом режиме и лучше так и поступать вместо блокировки).


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


    Правильно говорили про резолв айпишек с блокировкой проксей, впнов и хостингов. Как минимум таким образом делается детект поисковых ботов (двойной резолвинг айпи и результата в айпи и айпи при этом должны совпадать) без вайтлистинга (если нет желания или возможности или нет надобности в белых списках).


    Про тестовые куки и редиректы тоже хорошо, поверьте большинство ботов по нашей статистике (пусть она и небольшая — проекты не сильно большие, но все же она на реальных данных) не понимают js, против продвинутых сложно что-то сделать, но можно (та же рекаптча или кастомные проверки на js), хотя и не всех, правильно говорили серебряной пули нет.


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


    И из того что не говорили про то, что портянка в htaccess — это плохо, да так и есть, когда будет там пара тысяч строк, то ниче интересного из этого не получится, кроме того, когда понадобиться удалять из простыни какой-то определённый айпи и если это надо будет делать часто, то это не самое удобное занятие.


    Ещё хотел бы добавить, что можно проверять на правильность HTTP заголовков — это почти без оверхеда, но нужно понимать, что искать (тот же язык браузера, как минимум). Кроме этого, автору я бы посоветовал познакомиться с filter_var и фильтрами для айпи и заодно блокировать «неправильные» запросы, типа wp-login.php и остальных (с учетом переноса оригинальных страниц на другие УРЛ) и всякие ?page=‘—.


  1. WolfTheGrey
    27.10.2019 21:50

    Здесь, по-моему, не хватает одного важного дополнения или дисклеймера.
    Этим скриптом должны порезаться и боты ПС и другие от Majestic, Ahrefs и прочих важных сервисов. А это уже не хорошо для сайта.


    1. northmule Автор
      28.10.2019 08:27

      Боты кстати не режутся, так как к примеру Боты поиска Яндекс, делают максимум 10 запросов к сайту за 30 мин, но могут по 10-ь с разных IP. Боты Яндекс Метрика — могут сделать 1-2 запроса в 30 мин.
      Есть к примеру боты сервиса hypefactors.com и подобные (которые могут генерировать большое количество запросов). Мне в принципе такие боты на сайте не нужны, так как аудитория этого сайта — жители провинциального города РФ.


      1. WolfTheGrey
        28.10.2019 09:00

        Про Яндекс не скажу, под него нет больших проектов. Но очень многое зависит от размера проекта.
        У меня на паре проектов 100 тыс+ страниц Гугл пачками делает много запросов. Правда да, там оптимизировано сильно время отдачи страницы.
        Можно конечно сказать, что на таких проектах люди сами должны сообразить что можно, а что нельзя. Но когда «горит», то можно что-то и упустить. А восстанавливаться долго и мучительно после таких ошибок.