Potansiyel “kötü” botları tespit ediyoruz ve onları IP ile engelliyoruz

Potansiyel “kötü” botları tespit ediyoruz ve onları IP ile engelliyoruz

İyi günler! Yazıda size normal hosting kullanıcılarının sitede aşırı yük oluşturan IP adreslerini nasıl yakalayabileceklerini ve ardından barındırma araçlarını kullanarak bunları nasıl engelleyebileceklerini anlatacağım, "biraz" php kodu, birkaç ekran görüntüsü olacak.

Giriş verileri:

  1. CMS WordPress'te oluşturulmuş web sitesi
  2. Hosting Beget (bu bir reklam değildir, ancak yönetici paneli ekran görüntüleri bu özel barındırma sağlayıcısından olacaktır)
  3. WordPress sitesi 2000'li yılların başında açıldı ve çok sayıda makale ve materyal içeriyor
  4. PHP Sürüm 7.2
  5. WP en son sürüme sahip
  6. Bir süredir site, barındırma verilerine göre MySQL üzerinde yüksek bir yük oluşturmaya başladı. Her gün bu değer hesap başına normun %120'sini aştı
  7. Yandex'e göre. Metrica sitesi günde 100-200 kişi tarafından ziyaret ediliyor

Öncelikle şu yapıldı:

  1. Veritabanı tabloları birikmiş çöplerden temizlendi
  2. Gereksiz eklentiler devre dışı bırakıldı, güncel olmayan kod bölümleri kaldırıldı

Aynı zamanda önbellekleme seçeneklerinin (önbellek eklentileri) denendiğine, gözlemlerin yapıldığına - ancak bir siteden gelen% 120'lik yükün değişmediğine ve yalnızca büyüyebildiğine dikkatinizi çekmek isterim.

Barındırma veritabanlarındaki yaklaşık yük nasıl görünüyordu?

Potansiyel “kötü” botları tespit ediyoruz ve onları IP ile engelliyoruz
En üstte söz konusu site, hemen altında ise aynı cms'ye ve yaklaşık olarak aynı trafiğe sahip ancak daha az yük oluşturan diğer siteler yer almaktadır.

analizi

  • Verileri önbelleğe alma seçenekleriyle birçok girişimde bulunuldu, birkaç hafta boyunca gözlemler yapıldı (neyse ki bu süre zarfında barındırma bana çok kötü olduğumu ve bağlantımın kesileceğini yazmadı)
  • Yavaş sorgular için bir analiz ve arama yapıldı, ardından veritabanı yapısı ve tablo türü biraz değiştirildi
  • Analiz için öncelikle yerleşik AWStats'ı kullandık (bu arada, trafik hacmine göre en kötü IP adresinin hesaplanmasına yardımcı oldu)
  • Metrik - metrik, botlar hakkında değil, yalnızca kişiler hakkında bilgi sağlar
  • Ziyaretçileri bulundukları ülkeye ve çeşitli kombinasyonlara göre bile filtreleyebilen ve engelleyebilen WP eklentilerini kullanma girişimleri olmuştur.
  • Siteyi bir gün boyunca "Bakım altındayız" notuyla kapatmanın tamamen radikal bir yol olduğu ortaya çıktı - bu da ünlü eklenti kullanılarak yapıldı. Bu durumda yükün düşmesini ancak sıfır değerlerine kadar düşmemesini bekliyoruz, çünkü WP ideolojisi kancalara dayalıdır ve eklentiler bir "kanca" oluştuğunda faaliyetlerine başlar ve "kanca" oluşmadan önce veritabanına gelen istekler gönderilebilir. zaten yapılmış

Fikir

  1. Kısa sürede çok sayıda istekte bulunan IP adreslerini hesaplayın.
  2. Siteye yapılan isabet sayısını kaydedin
  3. İsabet sayısına göre siteye erişimi engelleyin
  4. .htaccess dosyasındaki "Reddet" girişinin kullanılmasını engelle
  5. Barındırma hakkında yazdığım için iptables ve Nginx kuralları gibi diğer seçenekleri dikkate almadım

Bir fikir ortaya çıktı, bu yüzden uygulanması gerekiyor, çünkü bu olmadan...

  • Veri biriktirmek için tablolar oluşturma
    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 yerleştireceğimiz bir dosya oluşturalım. Kod, engelleyici aday tablolarına kayıt yapacak ve hata ayıklama için bir geçmiş tutacaktır.

    IP adreslerini kaydetmek için dosya 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 özü ziyaretçinin IP adresini alıp bir tabloya yazmaktır. Eğer ip zaten tabloda mevcutsa cnt alanı artırılacaktır (siteye gelen istek sayısı)

  • Şimdi korkutucu olan şey... Şimdi yaptıklarımdan dolayı beni yakacaklar :)
    Siteye yapılan her isteği kaydetmek için dosya kodunu ana WordPress dosyasına (wp-load.php) bağlarız. Evet, çekirdek dosyasını değiştiriyoruz ve tam olarak $wpdb global değişkeni zaten var olduktan sonra değiştiriyoruz

Artık tablomuzda şu veya bu IP adresinin ne sıklıkla işaretlendiğini görebiliyoruz ve resmi anlamak için her 5 dakikada bir bir fincan kahve eşliğinde oraya bakıyoruz.

Potansiyel “kötü” botları tespit ediyoruz ve onları IP ile engelliyoruz

Daha sonra “zararlı” IP'yi kopyalayın, .htaccess dosyasını açın ve dosyanın sonuna ekleyin.

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

İşte bu, şimdi 94.242.55.248 - siteye erişimi yok ve veritabanında yük oluşturmuyor

Ancak her seferinde bu şekilde elle kopyalama yapmak pek doğru bir iş değildir ve ayrıca kodun özerk olması amaçlanmıştı.

Her 30 dakikada bir CRON aracılığıyla çalıştırılacak bir dosya ekleyelim:

.htaccess dosyasını değiştiren dosya kodu

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

Dosya kodu oldukça basit ve ilkel olup ana fikri, engelleme için adayları alıp, .htaccess dosyasındaki engelleme kurallarını yorumların arasına girmektir.
# start_auto_deny_list ve # end_auto_deny_list

Artık "zararlı" IP'ler kendileri tarafından engelleniyor ve .htaccess dosyası şuna benzer:

# 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

Sonuç olarak bu kod çalışmaya başladıktan sonra hosting panelinde sonucu görebilirsiniz:

Potansiyel “kötü” botları tespit ediyoruz ve onları IP ile engelliyoruz

Not: Materyal yazara aittir, her ne kadar bir kısmını web sitemde yayınlamış olsam da, Habre'de daha genişletilmiş bir versiyona sahibim.

Kaynak: habr.com

Yorum ekle