Kami mengira bot "jahat" yang berpotensi dan menyekatnya dengan IP

Kami mengira bot "jahat" yang berpotensi dan menyekatnya dengan IP

selamat hari! Dalam artikel saya akan memberitahu anda bagaimana pengguna pengehosan biasa boleh menangkap alamat IP yang menjana beban yang berlebihan di tapak dan kemudian menyekatnya menggunakan alat pengehosan, akan ada "sedikit" kod php, beberapa tangkapan skrin.

data input:

  1. Tapak web dibuat pada CMS WordPress
  2. Hosting Beget (ini bukan iklan, tetapi tangkapan skrin panel pentadbir adalah daripada penyedia pengehosan khusus ini)
  3. Tapak WordPress telah dilancarkan di suatu tempat pada awal tahun 2000 dan mempunyai sejumlah besar artikel dan bahan
  4. PHP versi 7.2
  5. WP mempunyai versi terkini
  6. Untuk beberapa waktu sekarang, laman web ini mula menjana beban yang tinggi pada MySQL mengikut data pengehosan. Setiap hari nilai ini melebihi 120% daripada norma setiap akaun
  7. Menurut Yandex. Tapak Metrica dikunjungi oleh 100-200 orang setiap hari

Pertama sekali, ini dilakukan:

  1. Jadual pangkalan data telah dibersihkan daripada sampah terkumpul
  2. Pemalam yang tidak diperlukan telah dilumpuhkan, bahagian kod lapuk telah dialih keluar

Pada masa yang sama, saya ingin menarik perhatian anda kepada fakta bahawa pilihan caching (pemalam caching) telah dicuba, pemerhatian telah dibuat - tetapi beban 120% dari satu tapak tidak berubah dan hanya boleh berkembang.

Apakah rupa anggaran beban pada pangkalan data pengehosan

Kami mengira bot "jahat" yang berpotensi dan menyekatnya dengan IP
Di bahagian atas ialah tapak yang dimaksudkan, tepat di bawah adalah tapak lain yang mempunyai cm yang sama dan lebih kurang trafik yang sama, tetapi menghasilkan kurang beban.

Analisis

  • Banyak percubaan dibuat dengan pilihan caching data, pemerhatian telah dijalankan selama beberapa minggu (nasib baik, selama ini pengehosan tidak pernah menulis kepada saya bahawa saya sangat teruk dan akan terputus sambungan)
  • Terdapat analisis dan carian untuk pertanyaan perlahan, kemudian struktur pangkalan data dan jenis jadual telah diubah sedikit
  • Untuk analisis, kami terutamanya menggunakan AWStats terbina dalam (secara langsung, ia membantu mengira alamat IP yang paling teruk berdasarkan volum trafik
  • Metrik - metrik memberikan maklumat hanya tentang orang, bukan tentang bot
  • Terdapat percubaan untuk menggunakan pemalam untuk WP yang boleh menapis dan menyekat pelawat walaupun mengikut negara lokasi dan pelbagai kombinasi
  • Cara yang benar-benar radikal ternyata adalah menutup tapak selama sehari dengan nota "Kami sedang diselenggara" - ini juga dilakukan menggunakan pemalam yang terkenal. Dalam kes ini, kami menjangkakan beban akan menurun, tetapi tidak kepada nilai sifar, kerana ideologi WP adalah berdasarkan cangkuk dan pemalam memulakan aktiviti mereka apabila "cangkuk" berlaku, dan sebelum "cangkuk" berlaku, permintaan kepada pangkalan data boleh sudah dibuat

Idea

  1. Kira alamat IP yang membuat banyak permintaan dalam tempoh yang singkat.
  2. Catatkan bilangan hits ke tapak
  3. Sekat akses ke tapak berdasarkan bilangan hits
  4. Sekat menggunakan entri "Tolak daripada" dalam fail .htaccess
  5. Saya tidak mempertimbangkan pilihan lain, seperti iptables dan peraturan untuk Nginx, kerana saya menulis tentang pengehosan

Idea telah muncul, jadi ia perlu dilaksanakan, kerana tanpa ini...

  • Mencipta jadual untuk mengumpul data
    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;
    
  • Mari buat fail di mana kita akan meletakkan kod tersebut. Kod akan merekodkan dalam jadual calon yang menyekat dan menyimpan sejarah untuk penyahpepijatan.

    Kod fail untuk merakam alamat 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);
    
    

    Intipati kod adalah untuk mendapatkan alamat IP pelawat dan menulisnya ke dalam jadual. Jika ip sudah ada dalam jadual, medan cnt akan ditambah (bilangan permintaan ke tapak)

  • Sekarang perkara yang menakutkan... Sekarang mereka akan membakar saya kerana tindakan saya :)
    Untuk merekodkan setiap permintaan ke tapak, kami menyambungkan kod fail ke fail WordPress utama - wp-load.php. Ya, kami menukar fail kernel dan tepat selepas pembolehubah global $wpdb sudah wujud

Jadi, sekarang kita dapat melihat berapa kerap alamat IP ini atau itu ditandakan dalam jadual kita dan dengan secawan kopi kita melihat di sana setiap 5 minit sekali untuk memahami gambar

Kami mengira bot "jahat" yang berpotensi dan menyekatnya dengan IP

Kemudian hanya salin IP "memudaratkan", buka fail .htaccess dan tambahkannya pada penghujung fail

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

Itu sahaja, kini 94.242.55.248 - tidak mempunyai akses ke tapak dan tidak menjana beban pada pangkalan data

Tetapi setiap kali menyalin dengan tangan seperti ini bukanlah tugas yang sangat baik, dan selain itu, kod itu bertujuan untuk menjadi autonomi

Mari tambahkan fail yang akan dilaksanakan melalui CRON setiap 30 minit:

Kod fail mengubah suai .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)));

Kod fail agak mudah dan primitif dan idea utamanya adalah untuk mengambil calon untuk menyekat dan memasukkan peraturan menyekat dalam fail .htaccess antara komen
# start_auto_deny_list dan # end_auto_deny_list

Kini IP "memudaratkan" disekat dengan sendirinya dan fail .htaccess kelihatan seperti ini:

# 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

Akibatnya, selepas kod ini mula berfungsi, anda boleh melihat hasilnya dalam panel pengehosan:

Kami mengira bot "jahat" yang berpotensi dan menyekatnya dengan IP

PS: Bahan ini adalah milik pengarang, walaupun saya menerbitkan sebahagian daripadanya di laman web saya, saya mendapat versi yang lebih diperluaskan pada Habre.

Sumber: www.habr.com

Tambah komen