نحسب الروبوتات "الشريرة" المحتملة ونحظرها بواسطة IP

نحسب الروبوتات "الشريرة" المحتملة ونحظرها بواسطة IP

يوم جيد! سأخبرك في المقالة كيف يمكن لمستخدمي الاستضافة العادية التقاط عناوين IP التي تولد حملًا زائدًا على الموقع ومن ثم حظرها باستخدام أدوات الاستضافة ، سيكون هناك كود php "قليلًا" ، بضع لقطات شاشة.

ادخال البيانات:

  1. تم إنشاء الموقع على CMS WordPress
  2. استضافة Beget (هذا ليس إعلانًا ، لكن شاشات الإدارة ستكون خاصة بمزود الاستضافة هذا)
  3. تم إطلاق موقع WordPress في وقت ما في أوائل عام 2000 ويحتوي على عدد كبير من المقالات والمواد
  4. PHP الإصدار 7.2
  5. WP لديه أحدث إصدار
  6. لبعض الوقت الآن ، بدأ الموقع في إنشاء حمل كبير على MySQL وفقًا للاستضافة. كل يوم تجاوزت هذه القيمة 120٪ من المعيار لكل حساب
  7. وفقًا لـ Yandex. يزور موقع Metrica الإلكتروني 100-200 شخص يوميًا

بادئ ذي بدء ، تم القيام به:

  1. تنظيف جداول قاعدة البيانات من القمامة المتراكمة
  2. تعطيل المكونات الإضافية غير الضرورية ، وإزالة أقسام من التعليمات البرمجية القديمة

في الوقت نفسه ، لفت انتباهك إلى حقيقة أن خيارات التخزين المؤقت (مكونات التخزين المؤقت) قد تمت تجربتها ، وتم إجراء الملاحظات - لكن الحمل بنسبة 120 ٪ من موقع واحد لم يتغير ويمكن أن ينمو فقط.

كيف بدا الحمل التقريبي على قواعد البيانات المستضافة

نحسب الروبوتات "الشريرة" المحتملة ونحظرها بواسطة IP
في الجزء العلوي يوجد الموقع المعني ، بينما يوجد أقل قليلاً من المواقع الأخرى التي لها نفس cms ونفس حركة المرور تقريبًا ، ولكنها تخلق حملاً أقل.

تحليل

  • تم إجراء العديد من المحاولات باستخدام خيارات تخزين البيانات مؤقتًا ، وتم إجراء ملاحظات لعدة أسابيع (لحسن الحظ ، لم تكتب لي الاستضافة أبدًا بأنني سيء للغاية وسوف يوقفونني عن العمل)
  • كان هناك تحليل وبحث عن استعلامات بطيئة ، ثم تم تغيير هيكل قاعدة البيانات ونوع الجداول بشكل طفيف
  • بالنسبة للتحليل ، استخدمنا بشكل أساسي AWStats المدمج (بالمناسبة ، ساعدنا في حساب عنوان IP الأكثر شرًا من خلال حجم حركة المرور
  • متري - يعطي المقياس معلومات عن الأشخاص فقط ، وليس عن برامج الروبوت
  • كانت هناك محاولات لاستخدام المكونات الإضافية لـ WP التي يمكنها تصفية الزوار وحظرهم حتى حسب بلد الإقامة ومن خلال مجموعات مختلفة
  • تبين أن هناك طريقة جذرية تمامًا تتمثل في إغلاق الموقع ليوم واحد بملاحظة "نحن قيد الصيانة" - وقد تم ذلك أيضًا باستخدام البرنامج المساعد الشهير. في هذه الحالة ، نتوقع أن ينخفض ​​الحمل ، ولكن ليس إلى قيم 0 يسار ، نظرًا لأن أيديولوجية WP تستند إلى الخطافات وتبدأ المكونات الإضافية نشاطها عند حدوث "الخطاف" ، وقبل حدوث "الخطاف" ، يتم إرسال الاستعلامات إلى يمكن بالفعل إنشاء قاعدة البيانات

فكرة

  1. احسب عناوين IP التي تقدم الكثير من الطلبات في فترة زمنية قصيرة.
  2. سجل عدد مرات الوصول إلى الموقع
  3. منع الوصول إلى الموقع بناءً على عدد الزيارات
  4. حظر باستخدام إدخال "رفض من" في ملف htaccess
  5. الخيارات الأخرى ، مثل iptables وقواعد Nginx ، لا تؤخذ في الاعتبار ، لأنني أكتب عن الاستضافة

ظهرت فكرة فلا بد من تنفيذها فكيف بدونها ...

  • إنشاء جداول لتجميع البيانات
    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;
    
  • لنقم بإنشاء ملف نضع فيه الكود. سيتم كتابة الكود في جداول الترشيح القفل والاحتفاظ بمحفوظات لتصحيح الأخطاء.

    رمز الملف لكتابة عناوين 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);
    
    

    جوهر الكود هو الحصول على عنوان IP للزائر وكتابته على الجدول. إذا كان ip موجودًا بالفعل في الجدول ، فسيتم زيادة حقل cnt (عدد الطلبات إلى الموقع)

  • الآن الأمر مخيف ... الآن سوف يحرقونني بسبب أفعالي 🙂
    لتسجيل كل طلب على الموقع ، نقوم بتضمين كود الملف في ملف WordPress الرئيسي - wp-load.php. نعم ، نحن بصدد تغيير ملف kernel وهذا بعد المتغير العام $ wpdb موجود بالفعل

لذلك ، يمكننا الآن معرفة عدد المرات التي يتم فيها تمييز عنوان IP هذا أو ذاك في طاولتنا ومع فنجان من القهوة ننظر هناك كل 5 دقائق لفهم الصورة

نحسب الروبوتات "الشريرة" المحتملة ونحظرها بواسطة IP

علاوة على ذلك ، قمنا بنسخ عنوان IP "الضار" ، وفتحنا ملف htaccess وأضفناه إلى نهاية الملف

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

كل شيء ، الآن 94.242.55.248 - ليس لديه حق الوصول إلى الموقع ولا ينتج عنه تحميل على قاعدة البيانات

ولكن في كل مرة لا يكون نسخها بيديك مهمة عادلة جدًا ، وإلى جانب ذلك ، تم تصميم الشفرة على أنها أداة مستقلة

دعنا نضيف ملفًا سيتم تنفيذه بواسطة CRON كل 30 دقيقة:

تعديل كود الملف .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)));

رمز الملف بسيط وبدائي للغاية ، وفكرته الرئيسية هي أخذ المرشحين للحظر وكتابة قواعد المنع في ملف htaccess بين التعليقات
# start_auto_deny_list و # end_auto_deny_list

يتم الآن حظر ips "الضارة" من تلقاء نفسها ، ويظهر ملف htaccess على النحو التالي:

# 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

نتيجة لذلك ، بعد بدء إجراء مثل هذا الرمز ، يمكنك رؤية النتيجة في لوحة الاستضافة:

نحسب الروبوتات "الشريرة" المحتملة ونحظرها بواسطة IP

ملاحظة: مادة المؤلف ، على الرغم من أنني نشرت جزءًا منها على موقع الويب الخاص بي ، إلا أن حبري تبين أنها نسخة أكثر شمولاً.

المصدر: www.habr.com

إضافة تعليق