Ons bereken potensiële "bose" bots en blokkeer hulle deur IP

Ons bereken potensiële "bose" bots en blokkeer hulle deur IP

Goeie dag! In die artikel sal ek jou vertel hoe gebruikers van gereelde hosting IP-adresse kan vang wat oormatige las op die werf genereer en dit dan blokkeer met behulp van gasheerinstrumente, daar sal ''n bietjie' php-kode wees, 'n paar skermkiekies.

Invoer data:

  1. Webwerf geskep op CMS WordPress
  2. Hosting Beget (dit is nie 'n advertensie nie, maar die administrasiepaneelskermkiekies sal van hierdie spesifieke gasheerverskaffer wees)
  3. Die WordPress-werf is iewers in die vroeë 2000 bekendgestel en het 'n groot aantal artikels en materiaal
  4. PHP weergawe 7.2
  5. WP het die nuutste weergawe
  6. Vir 'n geruime tyd het die webwerf 'n hoë las op MySQL begin genereer volgens die gasheerdata. Elke dag het hierdie waarde 120% van die norm per rekening oorskry
  7. Volgens Yandex. Metrica-werf word deur 100-200 mense per dag besoek

Eerstens is dit gedoen:

  1. Databasistabelle is skoongemaak van opgehoopte vullis
  2. Onnodige inproppe is gedeaktiveer, dele van verouderde kode is verwyder

Terselfdertyd wil ek u aandag daarop vestig dat kasopsies (caching plugins) probeer is, waarnemings gemaak is - maar die las van 120% vanaf een webwerf was onveranderd en kon net groei.

Hoe die benaderde lading op gasheerdatabasisse gelyk het

Ons bereken potensiële "bose" bots en blokkeer hulle deur IP
Aan die bokant is die betrokke webwerf, net onder is ander werwe wat dieselfde cms en ongeveer dieselfde verkeer het, maar minder vrag skep.

Analise

  • Baie pogings is aangewend met datakasopsies, waarnemings is oor 'n paar weke uitgevoer (gelukkig het die gasheer in hierdie tyd nooit vir my geskryf dat ek so sleg was en ontkoppel sou word nie)
  • Daar was 'n ontleding en soektog vir stadige navrae, toe is die databasisstruktuur en tabeltipe effens verander
  • Vir ontleding het ons hoofsaaklik die ingeboude AWStats gebruik (terloops, dit het gehelp om die slegste IP-adres te bereken op grond van verkeersvolume
  • Metriek - die metriek verskaf slegs inligting oor mense, nie oor bots nie
  • Daar was pogings om plugins vir WP te gebruik wat besoekers kan filter en blokkeer selfs volgens land van ligging en verskeie kombinasies
  • 'n Heeltemal radikale manier blyk te wees om die webwerf vir 'n dag te sluit met die nota "Ons is onder instandhouding" - dit is ook gedoen met behulp van die bekende inprop. In hierdie geval verwag ons dat die las sal daal, maar nie tot nul waardes nie, aangesien die WP-ideologie gebaseer is op hake en inproppe begin hul aktiwiteit wanneer 'n "haak" voorkom, en voordat die "haak" plaasvind, kan versoeke na die databasis reeds gemaak word

Idee

  1. Bereken IP-adresse wat baie versoeke in 'n kort tydperk rig.
  2. Teken die aantal treffers op die webwerf aan
  3. Blokkeer toegang tot die webwerf gebaseer op die aantal treffers
  4. Blokkeer deur die "Deny from"-inskrywing in die .htaccess-lêer te gebruik
  5. Ek het nie ander opsies oorweeg nie, soos iptables en reëls vir Nginx, want ek skryf oor hosting

'n Idee het verskyn, so dit moet geïmplementeer word, want sonder hierdie...

  • Skep tabelle om data te versamel
    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;
    
  • Kom ons skep 'n lêer waarin ons die kode sal plaas. Die kode sal in die blokkeerkandidaattabelle aanteken en 'n geskiedenis hou vir ontfouting.

    Lêerkode vir die opneem van IP-adresse

    <?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);
    
    

    Die kern van die kode is om die besoeker se IP-adres te kry en dit in 'n tabel te skryf. As die ip reeds in die tabel is, sal die cnt-veld verhoog word (die aantal versoeke na die webwerf)

  • Nou die skrikwekkende ding... Nou sal hulle my verbrand vir my dade :)
    Om elke versoek na die webwerf aan te teken, koppel ons die lêerkode aan die hoof WordPress-lêer - wp-load.php. Ja, ons verander die kernlêer en presies nadat die globale veranderlike $wpdb reeds bestaan

So, nou kan ons sien hoe gereeld hierdie of daardie IP-adres in ons tabel gemerk word en met 'n beker koffie kyk ons ​​een keer elke 5 minute daar om die prentjie te verstaan

Ons bereken potensiële "bose" bots en blokkeer hulle deur IP

Kopieer dan eenvoudig die "skadelike" IP, maak die .htaccess-lêer oop en voeg dit aan die einde van die lêer

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

Dit is dit, nou 94.242.55.248 - het nie toegang tot die webwerf nie en genereer nie las op die databasis nie

Maar elke keer om so met die hand te kopieer is nie 'n baie regverdige taak nie, en bowendien was die kode bedoel om outonoom te wees

Kom ons voeg 'n lêer by wat elke 30 minute via CRON uitgevoer sal word:

Lêerkode wysig .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)));

Die lêerkode is redelik eenvoudig en primitief en die hoofgedagte daarvan is om kandidate vir blokkering te neem en blokkeerreëls in die .htaccess-lêer tussen die opmerkings in te voer
# begin_outo_deny_list en # end_auto_deny_list

Nou word "skadelike" IP's deur hulself geblokkeer, en die .htaccess-lêer lyk so iets:

# 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

As gevolg hiervan, nadat hierdie kode begin werk het, kan u die resultaat in die gasheerpaneel sien:

Ons bereken potensiële "bose" bots en blokkeer hulle deur IP

NS: Die materiaal is die skrywer s'n, hoewel ek 'n gedeelte daarvan op my webwerf gepubliseer het, het ek 'n meer uitgebreide weergawe op Habre gekry.

Bron: will.com

Voeg 'n opmerking