Ne identifikojmë robotët e mundshëm "të këqij" dhe i bllokojmë ato me IP

Ne identifikojmë robotët e mundshëm "të këqij" dhe i bllokojmë ato me IP

Diten e mire! Në artikull do t'ju tregoj se si përdoruesit e pritjes së rregullt mund të kapin adresat IP që gjenerojnë ngarkesë të tepërt në sit dhe më pas t'i bllokojnë ato duke përdorur mjetet e pritjes, do të ketë "pak" kod php, disa pamje nga ekrani.

Fut te dhenat:

  1. Uebfaqja e krijuar në CMS WordPress
  2. Hosting Beget (kjo nuk është një reklamë, por pamjet e panelit të administratorit do të jenë nga ky ofrues i veçantë i pritjes)
  3. Faqja e WordPress u hap diku në fillim të vitit 2000 dhe ka një numër të madh artikujsh dhe materialesh
  4. Versioni PHP 7.2
  5. WP ka versionin më të fundit
  6. Prej disa kohësh, faqja filloi të gjenerojë një ngarkesë të lartë në MySQL sipas të dhënave të pritjes. Çdo ditë kjo vlerë kalonte 120% të normës për llogari
  7. Sipas Yandex. Faqja e Metrica vizitohet nga 100-200 persona në ditë

Para së gjithash, kjo u bë:

  1. Tabelat e bazës së të dhënave u pastruan nga mbeturinat e grumbulluara
  2. Shtojcat e panevojshme u çaktivizuan, seksionet e kodit të vjetëruar u hoqën

Në të njëjtën kohë, unë do të doja të tërhiqja vëmendjen tuaj për faktin se u provuan opsionet e memorizimit (shtojcat e memorizimit), u bënë vëzhgime - por ngarkesa prej 120% nga një sit ishte e pandryshuar dhe mund të rritet vetëm.

Si dukej ngarkesa e përafërt në bazat e të dhënave të pritjes

Ne identifikojmë robotët e mundshëm "të këqij" dhe i bllokojmë ato me IP
Në krye është faqja në fjalë, pak më poshtë janë faqet e tjera që kanë të njëjtën cms dhe afërsisht të njëjtin trafik, por krijojnë më pak ngarkesë.

Analizë

  • U bënë shumë përpjekje me opsionet e ruajtjes së të dhënave, vëzhgimet u kryen gjatë disa javësh (për fat të mirë, gjatë kësaj kohe hosti nuk më shkroi kurrë se isha kaq keq dhe do të shkëputesha)
  • Pati një analizë dhe kërkim për pyetje të ngadalta, më pas struktura e bazës së të dhënave dhe lloji i tabelës u ndryshuan pak
  • Për analizë, ne kemi përdorur kryesisht AWStats të integruar (nga rruga, ajo ndihmoi për të llogaritur adresën më të keqe IP bazuar në vëllimin e trafikut
  • Metrikë - metrika jep informacion vetëm për njerëzit, jo për robotët
  • Ka pasur përpjekje për të përdorur shtojca për WP që mund të filtrojnë dhe bllokojnë vizitorët edhe sipas vendit të vendndodhjes dhe kombinimeve të ndryshme
  • Një mënyrë krejtësisht radikale doli të ishte mbyllja e faqes për një ditë me shënimin "Ne jemi nën mirëmbajtje" - kjo u bë gjithashtu duke përdorur shtojcën e famshme. Në këtë rast, ne presim që ngarkesa të bjerë, por jo në vlera zero, pasi ideologjia WP bazohet në grepa dhe shtojcat fillojnë aktivitetin e tyre kur ndodh një "hook" dhe përpara se të ndodhë "hook", kërkesat në bazën e të dhënave mund të tashmë është bërë

Ide

  1. Llogaritni adresat IP që bëjnë shumë kërkesa në një periudhë të shkurtër kohe.
  2. Regjistroni numrin e goditjeve në sit
  3. Blloko aksesin në sit bazuar në numrin e vizitave
  4. Blloko duke përdorur hyrjen "Refuzo nga" në skedarin .htaccess
  5. Nuk mora në konsideratë opsione të tjera, si iptables dhe rregullat për Nginx, sepse po shkruaj për pritjen

Ka dalë një ide, ndaj duhet të zbatohet, pasi pa këtë...

  • Krijimi i tabelave për grumbullimin e të dhënave
    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;
    
  • Le të krijojmë një skedar në të cilin do të vendosim kodin. Kodi do të regjistrojë në tabelat e kandidatëve bllokues dhe do të mbajë një histori për korrigjimin e gabimeve.

    Kodi i skedarit për regjistrimin e adresave 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);
    
    

    Thelbi i kodit është të merrni adresën IP të vizitorit dhe ta shkruani atë në një tabelë. Nëse ip është tashmë në tabelë, fusha cnt do të rritet (numri i kërkesave në sit)

  • Tani gjëja e frikshme... Tani do më djegin për veprimet e mia :)
    Për të regjistruar çdo kërkesë në sajt, ne lidhim kodin e skedarit me skedarin kryesor të WordPress - wp-load.php. Po, ne ndryshojmë skedarin e kernelit dhe pikërisht pasi variabli global $wpdb ekziston tashmë

Pra, tani mund të shohim se sa shpesh shënohet kjo apo ajo adresë IP në tabelën tonë dhe me një filxhan kafe shikojmë atje një herë në 5 minuta për të kuptuar foton

Ne identifikojmë robotët e mundshëm "të këqij" dhe i bllokojmë ato me IP

Pastaj thjesht kopjoni IP-në "të dëmshme", hapni skedarin .htaccess dhe shtojeni në fund të skedarit

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

Kjo është ajo, tani 94.242.55.248 - nuk ka qasje në sit dhe nuk gjeneron ngarkesë në bazën e të dhënave

Por çdo herë që kopjimi me dorë si kjo nuk është një detyrë shumë e drejtë, dhe përveç kësaj, kodi synohej të ishte autonom

Le të shtojmë një skedar që do të ekzekutohet përmes CRON çdo 30 minuta:

Kodi i skedarit që modifikon .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)));

Kodi i skedarit është mjaft i thjeshtë dhe primitiv dhe ideja kryesore e tij është të marrë kandidatë për bllokim dhe të vendosë rregullat e bllokimit në skedarin .htaccess midis komenteve.
# start_auto_deny_list dhe # end_auto_deny_list

Tani IP-të "të dëmshme" janë bllokuar vetë, dhe skedari .htaccess duket diçka si kjo:

# 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

Si rezultat, pasi ky kod të fillojë të funksionojë, mund të shihni rezultatin në panelin pritës:

Ne identifikojmë robotët e mundshëm "të këqij" dhe i bllokojmë ato me IP

PS: Materiali është i autorit, megjithëse një pjesë të tij e kam publikuar në faqen time, kam marrë një version më të zgjeruar në Habre.

Burimi: www.habr.com

Shto një koment