Wy identifisearje potinsjele "kwea" bots en blokkearje se troch IP

Wy identifisearje potinsjele "kwea" bots en blokkearje se troch IP

Goeie! Yn it artikel sil ik jo fertelle hoe't brûkers fan reguliere hosting IP-adressen kinne fange dy't in oerstallige lading op 'e side generearje en se dan blokkearje mei hosting-ark, d'r sil "in bytsje" fan php-koade wêze, in pear skermôfbyldings.

Ynfier data:

  1. Webside makke op CMS WordPress
  2. Hosting Beget (dit is gjin advertinsje, mar de skermôfbyldings fan it adminpaniel sille fan dizze bepaalde hostingprovider komme)
  3. De WordPress-side waard earne yn 'e iere 2000 lansearre en hat in grut oantal artikels en materialen
  4. PHP ferzje 7.2
  5. WP hat de lêste ferzje
  6. Foar in skoft begon de side in hege lading op MySQL te generearjen neffens de hostinggegevens. Elke dei is dizze wearde mear as 120% fan 'e noarm per akkount
  7. Neffens Yandex. Metrica-side wurdt per dei besocht troch 100-200 minsken

Earst waard dit dien:

  1. Databanktabellen waarden wiske fan opboude jiskefet
  2. Unnedige plugins waarden útskeakele, seksjes fan ferâldere koade waarden fuortsmiten

Tagelyk wol ik jo oandacht lûke op it feit dat caching-opsjes (caching-plugins) waarden besocht, observaasjes waarden makke - mar de lading fan 120% fan ien side wie net feroare en koe allinich groeie.

Hoe de ûngefear lading op hostingdatabases der útseach

Wy identifisearje potinsjele "kwea" bots en blokkearje se troch IP
Oan de boppekant is de side yn kwestje, krekt ûnder binne oare siden dy't hawwe deselde cms en likernôch itselde ferkear, mar meitsje minder lading.

Analysis

  • In protte besykjen waarden makke mei opsjes foar gegevenscaching, observaasjes waarden útfierd oer ferskate wiken (gelokkich, yn dizze tiid hat de hosting my noait skreaun dat ik sa min wie en soe loskeppele wurde)
  • D'r wie in analyze en sykjen nei trage queries, doe waarden de databankstruktuer en tabeltype in bytsje feroare
  • Foar analyse brûkten wy primêr de ynboude AWStats (troch de manier, it holp om it minste IP-adres te berekkenjen op basis fan ferkearsvolume
  • Metrysk - de metrik jout allinich ynformaasje oer minsken, net oer bots
  • D'r binne besocht om plugins te brûken foar WP dy't besikers kinne filterje en blokkearje, sels troch lân fan lokaasje en ferskate kombinaasjes
  • In folslein radikale manier die bliken te wêzen om de side foar in dei te sluten mei de notysje "Wy binne ûnder ûnderhâld" - dit waard ek dien mei it ferneamde plugin. Yn dit gefal ferwachtsje wy dat de lading sakje sil, mar net nei nulwearden, om't de WP-ideology basearre is op heakken en plugins begjinne har aktiviteit as in "hook" optreedt, en foardat de "hook" foarkomt, kinne fersiken nei de databank al makke wurde

Idea

  1. Berekkenje IP-adressen dy't in protte oanfragen yn in koarte perioade meitsje.
  2. Record it oantal hits nei de side
  3. Blokkearje tagong ta de side basearre op it oantal hits
  4. Blokkearje mei de yngong "Dy fan" yn it .htaccess-bestân
  5. Ik haw oare opsjes net beskôge, lykas iptables en regels foar Nginx, om't ik skriuw oer hosting

Der is in idee ûntstien, dus it moat útfierd wurde, want sûnder dit...

  • Tabellen oanmeitsje om gegevens te sammeljen
    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;
    
  • Litte wy in bestân meitsje wêryn wy de koade pleatse. De koade sil opnimme yn 'e blokkearjende kandidatentabellen en in skiednis hâlde foar debuggen.

    Triemkoade foar it opnimmen fan IP-adressen

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

    De essinsje fan 'e koade is om it IP-adres fan' e besiker te krijen en it yn in tabel te skriuwen. As de ip al yn 'e tabel is, sil it cnt-fjild ferhege wurde (it oantal oanfragen nei de side)

  • No it enge ding... No sille se my ferbaarne foar myn dieden :)
    Om elk fersyk op 'e side op te nimmen, ferbine wy ​​de triemkoade oan it haad WordPress-bestân - wp-load.php. Ja, wy feroarje it kernelbestân en krekt nei't de globale fariabele $wpdb al bestiet

Dat, no kinne wy ​​sjen hoe faak dit of dat IP-adres yn ús tabel markearre is en mei in beker kofje sjogge wy dêr ien kear yn de 5 minuten om de foto te begripen

Wy identifisearje potinsjele "kwea" bots en blokkearje se troch IP

Kopiearje dan gewoan it "skealike" IP, iepenje it .htaccess-bestân en foegje it ta oan 'e ein fan it bestân

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

Dat is it, no 94.242.55.248 - hat gjin tagong ta de side en genereart gjin lading op 'e databank

Mar elke kear as dit kopiearje mei de hân is net in heul rjochtfeardige taak, en boppedat wie de koade bedoeld om autonoom te wêzen

Litte wy in bestân tafoegje dat elke 30 minuten fia CRON sil wurde útfierd:

Triem koade bewurkjen .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)));

De triemkoade is frij ienfâldich en primityf en har haadidee is om kandidaten te nimmen foar blokkearjen en blokkearjende regels yn te fieren yn it .htaccess-bestân tusken de opmerkingen
# start_auto_deny_list en # end_auto_deny_list

No wurde "skealike" IP's troch harsels blokkearre, en it .htaccess-bestân sjocht der sa út:

# 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 gefolch, nei't dizze koade begjint te wurkjen, kinne jo it resultaat sjen yn it hostingpaniel:

Wy identifisearje potinsjele "kwea" bots en blokkearje se troch IP

PS: It materiaal is fan de skriuwer, hoewol ik der in part fan publisearre op myn webside, krige ik in mear útwreide ferzje op Habre.

Boarne: www.habr.com

Add a comment