Potensial "pis" botları hesablayırıq və onları IP ilə bloklayırıq

Potensial "pis" botları hesablayırıq və onları IP ilə bloklayırıq

Yaxşı gün! Məqalədə sizə adi hostinq istifadəçilərinin saytda həddindən artıq yük yaradan IP ünvanlarını necə tuta biləcəyini və sonra hostinq alətlərindən istifadə edərək onları bloklaya biləcəyini söyləyəcəyəm, php kodunun “bir az”ı, bir neçə ekran görüntüsü olacaq.

Daxiletmə məlumatları:

  1. Veb sayt CMS WordPress-də yaradılmışdır
  2. Hosting Beget (bu bir reklam deyil, lakin admin panel ekran görüntüləri bu xüsusi hosting provayderindən olacaq)
  3. WordPress saytı 2000-ci ilin əvvəllərində istifadəyə verilmişdir və çoxlu sayda məqalə və materiallara malikdir
  4. PHP versiyası 7.2
  5. WP-nin ən son versiyası var
  6. Artıq bir müddətdir ki, sayt hostinq məlumatlarına görə MySQL-də yüksək yük yaratmağa başlayıb. Hər gün bu dəyər hesab üzrə normanın 120%-ni keçib
  7. Yandex-ə görə. Metrica saytını gündə 100-200 nəfər ziyarət edir

Əvvəlcə bu edildi:

  1. Verilənlər bazası cədvəlləri yığılmış zibildən təmizləndi
  2. Lazımsız plaginlər deaktiv edildi, köhnəlmiş kodun bölmələri silindi

Eyni zamanda, diqqətinizi cəlb etmək istərdim ki, caching variantları (caching plugins) sınaqdan keçirildi, müşahidələr aparıldı - lakin bir saytdan 120% yük dəyişmədi və yalnız böyüyə bilər.

Hostinq verilənlər bazalarına təxmini yük necə görünürdü

Potensial "pis" botları hesablayırıq və onları IP ilə bloklayırıq
Yuxarıda sözügedən sayt, bir az aşağıda eyni sms və təxminən eyni trafikə malik olan, lakin daha az yük yaradan digər saytlar var.

Təhlil

  • Məlumatların keşləşdirilməsi variantları ilə bir çox cəhdlər edildi, müşahidələr bir neçə həftə ərzində aparıldı (xoşbəxtlikdən, bu müddət ərzində hosting heç vaxt mənə belə pis olduğumu və əlaqəni kəsəcəyimi yazmadı)
  • Yavaş sorğular üçün təhlil və axtarış aparıldı, sonra verilənlər bazası strukturu və cədvəl növü bir qədər dəyişdirildi
  • Təhlil üçün biz ilk növbədə daxili AWStats-dan istifadə etdik (yeri gəlmişkən, bu, trafikin həcminə əsaslanaraq ən pis IP ünvanını hesablamağa kömək etdi.
  • Metrik - metrik botlar haqqında deyil, yalnız insanlar haqqında məlumat verir
  • WP üçün hətta yerləşdiyi ölkəyə və müxtəlif birləşmələrə görə ziyarətçiləri süzgəcdən keçirə və bloklaya bilən plaginlərdən istifadə etmək cəhdləri olmuşdur.
  • Tamamilə radikal bir yol, saytı bir gün ərzində "Biz baxım altındayıq" qeydi ilə bağlamaq oldu - bu da məşhur plagindən istifadə etməklə edildi. Bu halda biz yükün düşəcəyini gözləyirik, lakin sıfır dəyərlərə qədər yox, çünki WP ideologiyası qarmaqlara əsaslanır və plaginlər “çəngəl” baş verəndə öz fəaliyyətlərinə başlayır və “çəngəl” baş verməzdən əvvəl verilənlər bazasına sorğular ola bilər. artıq ediləcək

Fikir

  1. Qısa müddət ərzində çoxlu sorğular verən IP ünvanlarını hesablayın.
  2. Sayta daxil olanların sayını qeyd edin
  3. Xitlərin sayına görə sayta girişi bloklayın
  4. .htaccess faylında "Rədd etmə" girişindən istifadə edərək bloklayın
  5. İptables və Nginx qaydaları kimi digər variantları nəzərə almadım, çünki hostinq haqqında yazıram

İdeya yaranıb, ona görə də həyata keçirmək lazımdır, bunsuz da...

  • Məlumat toplamaq üçün cədvəllərin yaradılması
    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;
    
  • Kodu yerləşdirəcəyimiz bir fayl yaradaq. Kod bloklayan namizəd cədvəllərində qeyd edəcək və sazlama tarixini saxlayacaq.

    IP ünvanlarını qeyd etmək üçün fayl kodu

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

    Kodun mahiyyəti ziyarətçinin IP ünvanını almaq və onu cədvələ yazmaqdır. Əgər ip artıq cədvəldədirsə, cnt sahəsi artırılacaq (sayta edilən sorğuların sayı)

  • İndi qorxulu olan... İndi məni hərəkətlərimə görə yandıracaqlar :)
    Sayta edilən hər sorğunu qeyd etmək üçün biz fayl kodunu əsas WordPress faylına - wp-load.php-ə bağlayırıq. Bəli, biz kernel faylını dəyişirik və $wpdb qlobal dəyişəni artıq mövcud olduqdan sonra

Beləliklə, indi cədvəlimizdə bu və ya digər IP ünvanının nə qədər tez-tez qeyd olunduğunu görə bilərik və bir fincan qəhvə ilə şəkli başa düşmək üçün hər 5 dəqiqədə bir ora baxırıq.

Potensial "pis" botları hesablayırıq və onları IP ilə bloklayırıq

Sonra sadəcə “zərərli” IP-ni kopyalayın, .htaccess faylını açın və onu faylın sonuna əlavə edin.

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

Budur, indi 94.242.55.248 - sayta giriş yoxdur və verilənlər bazasında yük yaratmır

Ancaq hər dəfə belə əl ilə kopyalamaq çox düzgün iş deyil və bundan əlavə, kodun avtonom olması nəzərdə tutulurdu.

Hər 30 dəqiqədən bir CRON vasitəsilə yerinə yetiriləcək bir fayl əlavə edək:

.htaccess fayl kodunu dəyişdirir

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

Fayl kodu olduqca sadə və primitivdir və onun əsas ideyası bloklama üçün namizədləri götürmək və şərhlər arasında .htaccess faylına bloklama qaydalarını daxil etməkdir.
# start_avto_deny_list və # end_auto_deny_list

İndi "zərərli" IP-lər özləri tərəfindən bloklanır və .htaccess faylı belə görünür:

# 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

Nəticədə, bu kod işləməyə başladıqdan sonra nəticəni hosting panelində görə bilərsiniz:

Potensial "pis" botları hesablayırıq və onları IP ilə bloklayırıq

PS: Material müəllifə məxsusdur, onun bir hissəsini vebsaytımda dərc etsəm də, Habre-də daha geniş versiya əldə etdim.

Mənbə: www.habr.com

Добавить комментарий