Identifichemu potenziali bots "male" è bluccà per IP

Identifichemu potenziali bots "male" è bluccà per IP

Bella ghjurnata! In l'articulu vi dicu cumu l'utilizatori di l'ospitu regulare ponu catturà l'indirizzi IP chì generanu una carica eccessiva in u situ è ​​poi bluccà cù l'uttene di hosting, ci sarà "un pocu" di codice php, uni pochi di screenshots.

Dati di input:

  1. U situ web creatu nantu à CMS WordPress
  2. Hosting Beget (questu ùn hè micca un annunziu, ma i screenshots di u pannellu di amministrazione saranu da stu fornitore di hosting particulari)
  3. U situ di WordPress hè stata lanciata in un locu in u principiu di u 2000 è hà un gran numaru d'articuli è materiali
  4. Versione PHP 7.2
  5. WP hà l'ultima versione
  6. Dapoi qualchì tempu, u situ hà cuminciatu à generà una carica alta nantu à MySQL secondu e dati di hosting. Ogni ghjornu stu valore superava u 120% di a norma per contu
  7. Sicondu Yandex. U situ Metrica hè visitatu da 100-200 persone per ghjornu

Prima di tuttu, questu hè statu fattu:

  1. I tavule di basa di dati sò stati sbulicati da a basura accumulata
  2. I plugins innecessarii sò stati disattivati, rùbbriche di codice obsoleti sò stati eliminati

À u listessu tempu, vogliu attirà a vostra attenzione à u fattu chì l'opzioni di caching (plugins caching) sò stati pruvati, l'osservazioni sò state fatte - ma a carica di 120% da un situ ùn era micca cambiatu è puderia cresce solu.

Chì era a carica apprussimata nantu à e basa di dati di hosting

Identifichemu potenziali bots "male" è bluccà per IP
À a cima hè u situ in quistione, ghjustu sottu sò altri siti chì anu u stessu cms è apprussimatamente u stessu trafficu, ma creanu menu carica.

Analisi

  • Parechji tentativi sò stati fatti cù l'opzioni di cache di dati, l'osservazioni sò state realizate durante parechje settimane (per furtuna, in questu tempu, l'ospitu ùn m'hà mai scrittu chì eru cusì male è saria disconnected)
  • Ci hè stata una analisi è a ricerca di e dumande lente, dopu a struttura di a basa di dati è u tipu di tavula sò stati ligeramente cambiati
  • Per l'analisi, avemu utilizatu principalmente l'AWStats integrati (per via, hà aiutatu à calculà u peghju indirizzu IP basatu annantu à u voluminu di trafficu).
  • Metric - a metrica furnisce infurmazioni solu nantu à e persone, micca nantu à i bots
  • Ci sò stati tentativi di utilizà plugins per WP chì ponu filtrà è bluccà i visitatori ancu per paese di locu è diverse cumminazzioni.
  • Una manera completamente radicale hè stata per chjude u situ per un ghjornu cù a nota "Semu sottu mantenimentu" - questu hè ancu fattu cù u famosu plugin. In questu casu, aspittemu chì a carica falà, ma micca à cero valori, postu chì l'ideulugia WP hè basatu annantu à i ganci è i plugins cumincianu a so attività quandu un "ganciu" si trova, è prima chì u "ganciu" si faci, e dumande à a basa di dati pò esse. esse digià fattu

Idea

  1. Calculate l'indirizzi IP chì facenu assai richieste in pocu tempu.
  2. Registrate u numeru di hits à u situ
  3. Bloccà l'accessu à u situ basatu annantu à u numeru di hits
  4. Block usendu l'entrata "Deny from" in u schedariu .htaccess
  5. Ùn aghju micca cunsideratu altre opzioni, cum'è iptables è regule per Nginx, perchè aghju scrittu annantu à l'ospitu

Una idea hè apparsa, dunque deve esse implementata, cum'è senza questu...

  • Creazione di tavule per accumulà dati
    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;
    
  • Creemu un schedariu in quale avemu da mette u codice. U codice hà da arregistrà in i tavulini candidati di bloccu è mantene una storia per debugging.

    Codice di u schedariu per a registrazione di l'indirizzi 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);
    
    

    L'essenza di u codice hè di ottene l'indirizzu IP di u visitore è scrive in una tavula. Se l'ip hè digià in a tavula, u campu cnt serà aumentatu (u nùmeru di dumande à u situ)

  • Avà a cosa spaventosa... Avà mi brusgiaranu per i mo azzioni :)
    Per registrà ogni dumanda à u situ, cunnettamu u codice di u schedariu à u schedariu principale di WordPress - wp-load.php. Iè, cambiamu u schedariu di u kernel è precisamente dopu chì a variabile globale $wpdb esiste digià

Allora, avà pudemu vede quantu spessu questu o quellu indirizzu IP hè marcatu in a nostra tavula è cù una tazza di caffè ci guardemu una volta ogni 5 minuti per capiscenu a stampa.

Identifichemu potenziali bots "male" è bluccà per IP

Allora simpricimenti copiate l'IP "dannusu", apre u schedariu .htaccess è aghjunghje à a fine di u schedariu.

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

Hè questu, avà 94.242.55.248 - ùn hà micca accessu à u situ è ​​ùn genera micca carica nantu à a basa di dati

Ma ogni volta chì copià a manu cusì ùn hè micca un compitu assai ghjustu, è in più, u codice era destinatu à esse autonomu.

Aghjunghjemu un schedariu chì serà eseguitu via CRON ogni 30 minuti:

U codice di u schedariu mudificà .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)));

U codice di u schedariu hè abbastanza simplice è primitivu è a so idea principale hè di piglià i candidati per u bloccu è entre in e regule di bloccu in u schedariu .htaccess trà i cumenti.
# start_auto_deny_list è # end_auto_deny_list

Avà l'IP "dannusu" sò bluccati da elli stessi, è u schedariu .htaccess pare cusì:

# 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

In u risultatu, dopu chì stu codice cumencia à travaglià, pudete vede u risultatu in u pannellu di hosting:

Identifichemu potenziali bots "male" è bluccà per IP

PS: U materiale hè di l'autore, ancu s'ellu aghju publicatu una parte in u mo situ web, aghju avutu una versione più allargata nantu à Habre.

Source: www.habr.com

Add a comment