Kami mengidentifikasi potensi bot “jahat” dan memblokirnya berdasarkan IP

Kami mengidentifikasi potensi bot “jahat” dan memblokirnya berdasarkan IP

Selamat tinggal! Pada artikel saya akan memberi tahu Anda bagaimana pengguna hosting biasa dapat menangkap alamat IP yang menghasilkan beban berlebihan di situs dan kemudian memblokirnya menggunakan alat hosting, akan ada “sedikit” kode php, beberapa screenshot.

Memasukan data:

  1. Situs web dibuat di CMS WordPress
  2. Hosting Beget (ini bukan iklan, tetapi tangkapan layar panel admin akan diambil dari penyedia hosting khusus ini)
  3. Situs WordPress diluncurkan sekitar awal tahun 2000 dan memiliki banyak artikel dan materi
  4. PHP versi 7.2
  5. WP memiliki versi terbaru
  6. Untuk beberapa waktu sekarang, situs tersebut mulai menghasilkan beban tinggi di MySQL menurut data hosting. Setiap hari nilai ini melebihi 120% dari norma per akun
  7. Menurut Yandex. Situs Metrica dikunjungi 100-200 orang per hari

Hal pertama yang dilakukan adalah:

  1. Tabel database dibersihkan dari akumulasi sampah
  2. Plugin yang tidak diperlukan telah dinonaktifkan, bagian kode yang sudah ketinggalan zaman telah dihapus

Pada saat yang sama, saya ingin menarik perhatian Anda pada fakta bahwa opsi caching (plugin caching) telah dicoba, pengamatan telah dilakukan - tetapi beban 120% dari satu situs tidak berubah dan hanya dapat bertambah.

Seperti apa perkiraan beban pada database hosting

Kami mengidentifikasi potensi bot “jahat” dan memblokirnya berdasarkan IP
Di bagian atas adalah situs yang dimaksud, tepat di bawah adalah situs lain yang memiliki cms yang sama dan lalu lintas yang kurang lebih sama, tetapi memuat lebih sedikit.

analisis

  • Banyak upaya dilakukan dengan opsi cache data, pengamatan dilakukan selama beberapa minggu (untungnya selama ini pihak hosting tidak pernah menulis kepada saya bahwa saya sangat buruk dan akan terputus)
  • Terjadi analisis dan pencarian query yang lambat, kemudian struktur database dan tipe tabel sedikit diubah
  • Untuk analisis, kami terutama menggunakan AWStats bawaan (omong-omong, ini membantu menghitung alamat IP terburuk berdasarkan volume lalu lintas
  • Metrik - metrik hanya memberikan informasi tentang orang, bukan tentang bot
  • Ada upaya untuk menggunakan plugin untuk WP yang dapat memfilter dan memblokir pengunjung bahkan berdasarkan negara lokasi dan berbagai kombinasi
  • Ternyata cara yang benar-benar radikal adalah dengan menutup situs selama sehari dengan catatan "Kami sedang dalam pemeliharaan" - ini juga dilakukan menggunakan plugin terkenal. Dalam hal ini, kami memperkirakan beban akan turun, tetapi tidak ke nilai nol, karena ideologi WP didasarkan pada hook dan plugin memulai aktivitasnya ketika "hook" terjadi, dan sebelum "hook" terjadi, permintaan ke database dapat sudah dibuat

Ide

  1. Hitung alamat IP yang membuat banyak permintaan dalam waktu singkat.
  2. Catat jumlah kunjungan ke situs
  3. Blokir akses ke situs berdasarkan jumlah klik
  4. Blokir menggunakan entri “Tolak dari” di file .htaccess
  5. Saya tidak mempertimbangkan opsi lain, seperti iptables dan aturan untuk Nginx, karena saya menulis tentang hosting

Sebuah ide sudah muncul, sehingga perlu diimplementasikan, karena tanpa ini...

  • Membuat tabel untuk mengumpulkan 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 file di mana kita akan menempatkan kodenya. Kode akan mencatat dalam tabel kandidat pemblokiran dan menyimpan riwayat untuk debugging.

    Kode file untuk mencatat 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);
    
    

    Inti dari kode ini adalah mendapatkan alamat IP pengunjung dan menuliskannya ke dalam tabel. Jika ip sudah ada di tabel, kolom cnt akan bertambah (jumlah permintaan ke situs)

  • Sekarang hal yang menakutkan... Sekarang mereka akan membakar saya karena tindakan saya :)
    Untuk merekam setiap permintaan ke situs, kami menghubungkan kode file ke file utama WordPress - wp-load.php. Ya, kita ubah file kernelnya dan tepatnya setelah variabel global $wpdb sudah ada

Jadi, sekarang kita dapat melihat seberapa sering alamat IP ini atau itu ditandai di tabel kita dan dengan secangkir kopi kita melihat ke sana setiap 5 menit sekali untuk memahami gambarnya.

Kami mengidentifikasi potensi bot “jahat” dan memblokirnya berdasarkan IP

Kemudian cukup salin IP “berbahaya”, buka file .htaccess dan tambahkan di akhir file

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

Itu saja, sekarang 94.242.55.248 - tidak memiliki akses ke situs dan tidak memuat database

Namun setiap kali menyalin dengan tangan seperti ini bukanlah tugas yang benar, dan selain itu, kode tersebut dimaksudkan untuk bersifat otonom

Mari tambahkan file yang akan dieksekusi melalui CRON setiap 30 menit:

Memodifikasi kode file .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)));

Kode file cukup sederhana dan primitif dan ide utamanya adalah mengambil kandidat pemblokiran dan memasukkan aturan pemblokiran di file .htaccess di antara komentar
# start_auto_deny_list dan # end_auto_deny_list

Sekarang IP “berbahaya” diblokir dengan sendirinya, dan file .htaccess terlihat 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

Hasilnya, setelah kode ini mulai berfungsi, Anda dapat melihat hasilnya di panel hosting:

Kami mengidentifikasi potensi bot “jahat” dan memblokirnya berdasarkan IP

PS: Materinya milik penulis, walaupun sebagian saya terbitkan di website saya, saya mendapat versi yang lebih luas di Habre.

Sumber: www.habr.com

Tambah komentar