Біз ықтимал «зұлымдық» боттарды анықтаймыз және оларды IP арқылы блоктаймыз

Біз ықтимал «зұлымдық» боттарды анықтаймыз және оларды IP арқылы блоктаймыз

Қайырлы күн! Мақалада мен сізге тұрақты хостинг пайдаланушылары сайтта шамадан тыс жүктемені тудыратын IP мекенжайларын қалай ұстай алатынын айтып беремін, содан кейін оларды хостинг құралдары арқылы бұғаттаймын, PHP кодын «аздап» болады, бірнеше скриншоттар болады.

Енгізілген деректер:

  1. CMS WordPress жүйесінде жасалған веб-сайт
  2. Hosting Beget (бұл жарнама емес, бірақ әкімші панелінің скриншоттары осы хостинг провайдерінен болады)
  3. WordPress сайты 2000 жылдың басында іске қосылды және көптеген мақалалар мен материалдарға ие
  4. PHP нұсқасы 7.2
  5. WP соңғы нұсқасы бар
  6. Біраз уақыттан бері сайт хостинг деректеріне сәйкес MySQL-ге жоғары жүктеме жасай бастады. Күн сайын бұл көрсеткіш шоттағы нормадан 120% асып түсті
  7. Яндекс бойынша. Metrica сайтына күніне 100-200 адам кіреді

Ең алдымен, бұл жасалды:

  1. Деректер базасының кестелері жинақталған қоқыстан тазартылды
  2. Қажет емес плагиндер өшірілді, ескірген код бөлімдері жойылды

Сонымен бірге, мен сіздің назарыңызды кэштеу опциялары (кэштеу плагиндері) қолданылғанына, бақылаулар жасалғанына назар аударғым келеді - бірақ бір сайттан 120% жүктеме өзгеріссіз қалды және тек өсе алады.

Хостинг дерекқорларына шамамен жүктеме қандай болды

Біз ықтимал «зұлымдық» боттарды анықтаймыз және оларды IP арқылы блоктаймыз
Жоғарғы жағында қарастырылып жатқан сайт, дәл төменде бірдей см-ге ие және шамамен бірдей трафикке ие, бірақ аз жүктеме жасайтын басқа сайттар бар.

Талдау

  • Деректерді кэштеу опцияларымен көптеген әрекеттер жасалды, бақылаулар бірнеше апта бойы жүргізілді (бақытымызға орай, осы уақыт ішінде хостинг маған ешқашан жаман екенімді және ажыратылатынымды жазған жоқ)
  • Баяу сұрауларды талдау және іздеу болды, содан кейін деректер қорының құрылымы мен кесте түрі сәл өзгертілді
  • Талдау үшін біз ең алдымен кірістірілген AWStats қолдандық (айтпақшы, ол трафик көлеміне негізделген ең нашар IP мекенжайын есептеуге көмектесті.
  • Метрика - метрика боттар туралы емес, тек адамдар туралы ақпаратты береді
  • WP үшін кірушілерді тіпті орналасқан елі және әртүрлі комбинациялар бойынша сүзуге және блоктауға болатын плагиндерді пайдалану әрекеттері болды.
  • «Бізге техникалық қызмет көрсетілуде» деген жазбамен сайтты бір күнге жабудың түбегейлі тәсілі болды - бұл әйгілі плагин арқылы жасалды. Бұл жағдайда жүктеме төмендейді деп күтеміз, бірақ нөлдік мәндерге дейін емес, өйткені WP идеологиясы ілмектерге негізделген және плагиндер «ілмек» пайда болған кезде өз әрекетін бастайды және «ілмек» пайда болғанға дейін дерекқорға сұраулар қазірдің өзінде жасалған

Идея

  1. Қысқа уақыт ішінде көп сұраныс жасайтын IP мекенжайларын есептеңіз.
  2. Сайтқа кіру санын жазыңыз
  3. Хит санына қарай сайтқа кіруді бұғаттау
  4. .htaccess файлындағы «Бас тарту» жазбасын пайдаланып блоктаңыз
  5. Мен Nginx үшін iptables және ережелер сияқты басқа опцияларды қарастырмадым, өйткені мен хостинг туралы жазып жатырмын

Идея пайда болды, сондықтан оны жүзеге асыру керек, онсыз да...

  • Мәліметтерді жинақтау үшін кестелер құру
    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 арқылы блоктаймыз

Содан кейін жай ғана «зиянды» 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 - сайтқа кіру мүмкіндігі жоқ және дерекқорға жүктеме жасамайды.

Бірақ әр жолы қолмен көшіру өте әділ тапсырма емес, сонымен қатар код автономды болуға арналған.

Әр 30 минут сайын CRON арқылы орындалатын файлды қосамыз:

.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 файлында блоктау ережелерін енгізу болып табылады.
# бастау_авто_қабылдамау_тізімі және # автоматты_бас тарту_тізімін аяқтау

Енді «зиянды» 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

Нәтижесінде, осы код жұмыс істей бастағаннан кейін нәтижені хостинг тақтасында көре аласыз:

Біз ықтимал «зұлымдық» боттарды анықтаймыз және оларды IP арқылы блоктаймыз

PS: Материал авторлық, мен оның бір бөлігін веб-сайтымда жариялағаныммен, мен Habre-де кеңейтілген нұсқасын алдым.

Ақпарат көзі: www.habr.com

пікір қалдыру