Arvutame potentsiaalsed "kurjad" botid ja blokeerime need IP-aadresside alusel

Arvutame potentsiaalsed "kurjad" botid ja blokeerime need IP-aadresside alusel

Tere! Selles artiklis räägin, kuidas saavad tavalise hostingu kasutajad tuvastada IP-aadresse, mis tekitavad teie veebisaidile liigset koormust, ja seejärel neid hostingu tööriistade abil blokeerida. Siin on veidi php koodi ja mõned ekraanipildid.

Sisendandmed:

  1. Veebisait, mis on loodud CMS WordPressil
  2. Veebimajutus Beget (see ei ole reklaam, kuid ekraanipildid adminpaneelist on just selle hostimisteenuse pakkuja)
  3. WordPressi sait käivitus kuskil 2000. aastate alguses ja sisaldab suurt hulka artikleid ja materjale.
  4. PHP versioon 7.2
  5. WP-l on viimane versioon.
  6. Viimasel ajal on sait hakanud MySQL-i koormust genereerima, vastavalt hostingu andmetele. Iga päev ületas see väärtus 120% normist konto jaoks.
  7. Yandex.Metrika andmetel külastab veebisaiti iga päev 100-200 inimest.

Esiteks tehti järgmist:

  1. Andmebaasi tabelid puhastati kuhjunud prügist.
  2. Keelati tarbetud pistikprogrammid, eemaldati aegunud koodijupid.

Samas juhin tähelepanu, et prooviti mitmeid vahemällu salvestamise valikuid (vahemälupistikprogramme), tehti jälgimisi — aga 120% koormus ühest veebisaidist jäi muutumatuks ja võis ainult kasvada.

Nii nägi välja ligikaudne koormus hostingu andmebaasidele.

Arvutame potentsiaalsed "kurjad" botid ja blokeerime need IP-aadresside alusel
Tippu asub veebisait, millest räägitakse, veidi allpool on teised saidid, mis kasutavad sama CMS-i ja omavad umbes sama külastatavust, kuid tekitavad väiksemat koormust.

Analüüs

  • Tehti palju katsetusi andmete vahemällu salvestamise variantidega, jälgiti mitu nädalat (õnneks ei ole hostimine mulle selle aja jooksul kordagi kirjutanud, et ma olen nii halb ja nad lülitavad mind välja).
  • Tehti analüüs ja aeglaste päringute otsing, seejärel muudeti veidi andmebaasi struktuuri ja tabelitüüpe.
  • Analüüsi jaoks kasutati esmalt sisseehitatud AWStats'i (see aitas tegelikult tuvastada kõige pahatahtlikuma IP-aadressi liiklusmahu järgi).
  • Metrika — metrika annab teavet ainult inimeste, mitte robotite kohta.
  • Prooviti kasutada pistikprogramme WP-le, mis suudavad filtreerida ja blokeerida külastajaid isegi nende asukoha ja erinevate kombinatsioonide järgi.
  • Radikaalne viis, kuidas sulgeda saidi juurde pääs üheks päevaks sildiga „Meie teeme tehnilist hooldust“, on samuti teostatud kuulsale pistikprogrammile toetudes. Sel juhul oodata, et koormus langeb, kuid mitte null-väärtusteni, kuna WP ideoloogia põhineb huukidel ja pistikprogrammid alustavad oma tegevust, kui mõni „huuk“ saabub, ja enne „huugi“ saabumist võivad juba olla tehtud päringud andmebaasi.

Idee

  1. Kalkuleerida IP-aadresse, mis teevad palju päringuid lühikese aja jooksul.
  2. Fikseerida saidi pöördumiste arv.
  3. Sõltuvalt pöördumiste arvust blokeerida juurdepääs saidile.
  4. Blokeerida „Deny from“ kirje abil .htaccess failis.
  5. Teised variandid, nagu iptables ja reeglid Nginxis, ei tule arvesse, kuna kirjutan hostimisest.

Idee on sündinud, nüüd tuleb see ellu viia, kuidas muidu…

  • Loome tabelid andmete kogumiseks.
    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='Kandidaadid blokeerimiseks'
    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='Juba blokeeritud nimekiri'
    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='Kõikide päringute ajalugu debugeerimiseks'
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=1;
    
  • Loome faili, kuhu paneme koodi. Kood paneb kirja blokkimiseks kandidaadid ja hoiab ajalugu debugeerimiseks.

    Faili kood IP-aadresside salvestamiseks.

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

    Koodi olemus on saada külastaja IP-aadress ja salvestada see tabelisse. Kui IP on juba tabelis olemas, suurendatakse cnt (päringute arvu saidile).

  • Nüüd tuleb hirmuäratav… Praegu põletatakse mind mu tegevuste tõttu 🙂.
    Selleks, et salvestada iga pöördumine saidile, ühendame faili koodi WordPressi põhifailiga — wp-load.php. Jah, just see on juba olemasoleva globaalse muutuja $wpdb muutmine.

Nüüd näeme, kui sageli mõni IP-aadress meie tabelis esindatud on, ja võtame iga 5 minuti tagant tassikese kohvi kõrvale, et sinna piiluda ja paremini aru saada, mis toimub.

Arvutame potentsiaalsed "kurjad" botid ja blokeerime need IP-aadresside alusel

Seejärel kopeerige "kahjulik" IP, avage fail .htaccess ja lisage see faili lõppu.

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

Nüüd on 94.242.55.248 saidile juurdepääs keelatud ja see ei genereeri koormust andmebaasile.

Kuid iga kord on nii käsitsi kopeerimine üsna tüütu ja kood oli algselt mõeldud autonoomseks.

Lisame faili, mis käivitatakse CRON-i kaudu iga 30 minuti järel:

Kood, mis muudab .htaccess faili

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

$new_blocked = [];

$exclude_ip = [
    '87.236.16.70' //hosting IP
];

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;
}

// Kustutatakse tabel
$wpdb->query("DELETE FROM wp_visiters_bot");

//$file = '.htaccess';

$start_searche_tag = 'start_auto_deny_list';

$end_searche_tag = 'end_auto_deny_list';

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

    $replace_string = ''; // Test string for .htaccess file

    $target_content = false; // Flag for the desired code section

    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 "Error: fgets() unexpectedly failed";
    }
    fclose($handle);
}

// Current .htaccess file
$content = file_get_contents($file);

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

// Clear all blocks in .htaccess file
file_put_contents($file, $content);

// Write new blocks
$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)));

Faili kood on piisavalt lihtne ja algne ning selle peamine idee on võtta blokeerimise kandidaadid ja kirjutada blokeerimise reeglid faili .htaccess kommentaaride vahele.
# start_auto_deny_list и # end_auto_deny_list

Nüüd blokeeritakse "kahjulikud" IP-d ise ning .htaccess fail näeb välja umbes selline:

# 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

Kokkuvõttes, pärast sellise koodi rakendamist on tulemuse nägemine võimalik hostimise paneelil:

Arvutame potentsiaalsed "kurjad" botid ja blokeerime need IP-aadresside alusel

PS: Materjal on autoriteos, kuigi osa olen avaldanud oma saidil, on Habres välja tulnud ulatuslikum versioon.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster