เราระบุบอทที่ “ชั่วร้าย” ที่อาจเกิดขึ้นและบล็อกพวกมันด้วย IP

เราระบุบอทที่ “ชั่วร้าย” ที่อาจเกิดขึ้นและบล็อกพวกมันด้วย IP

ขอให้เป็นวันที่ดี! ในบทความฉันจะบอกคุณว่าผู้ใช้โฮสติ้งทั่วไปสามารถจับที่อยู่ IP ที่สร้างภาระมากเกินไปบนไซต์แล้วบล็อกพวกเขาโดยใช้เครื่องมือโฮสติ้งได้อย่างไร จะมีโค้ด php "เล็กน้อย" ภาพหน้าจอบางส่วน

ป้อนข้อมูล:

  1. เว็บไซต์ที่สร้างบน CMS WordPress
  2. Hosting Beget (นี่ไม่ใช่โฆษณา แต่ภาพหน้าจอแผงผู้ดูแลระบบจะมาจากผู้ให้บริการโฮสติ้งรายนี้)
  3. ไซต์ WordPress เปิดตัวที่ไหนสักแห่งในต้นปี 2000 และมีบทความและสื่อจำนวนมาก
  4. PHP เวอร์ชัน 7.2
  5. WP มีเวอร์ชันล่าสุด
  6. ในขณะนี้ ไซต์เริ่มสร้างภาระงานสูงบน MySQL ตามข้อมูลโฮสติ้ง ทุกวันมูลค่านี้เกิน 120% ของบรรทัดฐานต่อบัญชี
  7. ตามข้อมูลของยานเดกซ์ มีผู้เยี่ยมชมไซต์ Metrica 100-200 คนต่อวัน

ก่อนอื่นสิ่งนี้เสร็จสิ้น:

  1. ตารางฐานข้อมูลถูกกำจัดขยะที่สะสม
  2. ปลั๊กอินที่ไม่จำเป็นถูกปิดใช้งาน ส่วนของโค้ดที่ล้าสมัยถูกลบออก

ในเวลาเดียวกันฉันอยากจะดึงความสนใจของคุณไปที่ความจริงที่ว่ามีการลองใช้ตัวเลือกแคช (ปลั๊กอินแคช) มีการสังเกต - แต่โหลด 120% จากไซต์เดียวไม่เปลี่ยนแปลงและสามารถเติบโตได้เท่านั้น

ภาระงานโดยประมาณบนฐานข้อมูลโฮสติ้งเป็นอย่างไร

เราระบุบอทที่ “ชั่วร้าย” ที่อาจเกิดขึ้นและบล็อกพวกมันด้วย IP
ที่ด้านบนคือไซต์ที่เป็นปัญหา ด้านล่างคือไซต์อื่นๆ ที่มี cms เท่ากันและมีปริมาณการรับส่งข้อมูลเท่ากัน แต่สร้างภาระงานน้อยกว่า

การวิเคราะห์

  • มีความพยายามหลายครั้งกับตัวเลือกการแคชข้อมูล การสังเกตได้ดำเนินการเป็นเวลาหลายสัปดาห์ (โชคดีที่ในช่วงเวลานี้โฮสติ้งไม่เคยเขียนถึงฉันว่าฉันแย่มากและจะถูกตัดการเชื่อมต่อ)
  • มีการวิเคราะห์และค้นหาการสืบค้นที่ช้า โครงสร้างฐานข้อมูลและประเภทตารางจึงมีการเปลี่ยนแปลงเล็กน้อย
  • สำหรับการวิเคราะห์ เราใช้ AWStats ในตัวเป็นหลัก (อย่างไรก็ตาม ช่วยคำนวณที่อยู่ IP ที่แย่ที่สุดตามปริมาณการรับส่งข้อมูล
  • ตัวชี้วัด - ตัวชี้วัดให้ข้อมูลเกี่ยวกับผู้คนเท่านั้น ไม่เกี่ยวกับบอท
  • มีความพยายามที่จะใช้ปลั๊กอินสำหรับ WP ที่สามารถกรองและบล็อกผู้เยี่ยมชมได้ แม้จะแยกตามประเทศของที่ตั้งและชุดค่าผสมต่างๆ
  • วิธีที่รุนแรงอย่างสิ้นเชิงคือการปิดไซต์เป็นเวลาหนึ่งวันโดยมีข้อความว่า "เรากำลังอยู่ระหว่างการบำรุงรักษา" - ซึ่งทำได้โดยใช้ปลั๊กอินที่มีชื่อเสียง ในกรณีนี้ เราคาดว่าโหลดจะลดลง แต่ไม่ใช่ค่าศูนย์ เนื่องจากอุดมการณ์ WP ขึ้นอยู่กับ hooks และปลั๊กอินเริ่มต้นกิจกรรมเมื่อมี "hook" เกิดขึ้น และก่อนที่ "hook" จะเกิดขึ้น คำขอไปยังฐานข้อมูลสามารถทำได้ ได้ทำไปแล้ว

ความคิด

  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 ใช่ เราเปลี่ยนไฟล์เคอร์เนลและหลังจากที่ตัวแปรโกลบอล $wpdb มีอยู่แล้ว

ตอนนี้เราสามารถเห็นได้ว่าที่อยู่ IP นี้หรือที่อยู่ 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

ตอนนี้ IP ที่ "เป็นอันตราย" จะถูกบล็อกด้วยตัวเอง และไฟล์ .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

PS: เนื้อหานี้เป็นของผู้เขียน แม้ว่าฉันจะเผยแพร่บางส่วนบนเว็บไซต์ของฉัน แต่ฉันก็มี Habre เวอร์ชันที่ขยายมากขึ้น

ที่มา: will.com

เพิ่มความคิดเห็น