Биз потенциалдуу "жаман" ботторду эсептеп, аларды IP аркылуу бөгөттөйбүз

Биз потенциалдуу "жаман" ботторду эсептеп, аларды IP аркылуу бөгөттөйбүз

Кайырдуу күн! Макалада мен сизге айтып берем, кадимки хостингдин колдонуучулары сайтта ашыкча жүктөмдү пайда кылган IP даректерди кантип кармап, анан хостинг куралдарын колдонуу менен аларды бөгөттөй алышат, PHP кодун "бир аз" болот, бир нече скриншот.

Киргизүү дайындары:

  1. CMS WordPressте түзүлгөн веб-сайт
  2. Хостинг Beget (бул жарнама эмес, бирок администратор панелинин скриншоттору ушул хостинг провайдеринен болот)
  3. WordPress сайты 2000-жылдын башында ачылган жана көптөгөн макалаларды жана материалдарды камтыйт
  4. PHP версиясы 7.2
  5. WP эң акыркы версиясына ээ
  6. Бир нече убакыттан бери сайт хостинг маалыматтарына ылайык MySQLде жогорку жүктү түзө баштады. Кун сайын бул керсеткуч нормадан 120 процентке ашты
  7. Яндекс боюнча. Metrica сайтына күнүнө 100-200 адам кирет

Биринчиден, бул жасалды:

  1. Маалыматтар базасынын таблицалары топтолгон таштандылардан тазаланды
  2. Керексиз плагиндер өчүрүлүп, эскирген коддун бөлүмдөрү алынып салынды

Ошол эле учурда, мен сиздин көңүлүңүздү бургум келет, бул кэштөө параметрлери (кэштөө плагиндери) аракет кылынган, байкоолор жүргүзүлгөн - бирок бир сайттан 120% жүк өзгөргөн эмес жана өсө алган.

Хостинг маалыматтар базасына болжолдуу жүк кандай көрүндү

Биз потенциалдуу "жаман" ботторду эсептеп, аларды IP аркылуу бөгөттөйбүз
Жогору жакта каралып жаткан сайт, ылдыйда бирдей смс жана болжол менен бирдей трафикке ээ, бирок азыраак жүктөмдү жараткан башка сайттар.

талдоо

  • Дайындарды кэштөө опциялары менен көптөгөн аракеттер жасалды, байкоолор бир нече жума бою жүргүзүлдү (бактыга жараша, бул убакыттын ичинде хостинг мага эч качан жаман экенимди жана өчүрүлөт деп жазган эмес)
  • Жай сурамдарды талдоо жана издөө болду, андан кийин маалымат базасынын түзүмү жана таблица түрү бир аз өзгөртүлдү
  • Талдоо үчүн биз биринчи кезекте орнотулган AWStats колдондук (баса, ал трафиктин көлөмүнүн негизинде эң начар IP даректи эсептөөгө жардам берди.
  • Метрика - метрика боттор жөнүндө эмес, адамдар жөнүндө гана маалымат берет
  • WP үчүн плагиндерди колдонуу аракеттери болду, алар келгендерди жайгашкан өлкө жана ар кандай комбинациялар боюнча чыпкалап, бөгөттөй алат.
  • Толугу менен радикалдуу жолу "Биз тейлөөдө" деген жазуу менен сайтты бир күнгө жабуу болду - бул белгилүү плагиндин жардамы менен жасалган. Бул учурда, биз жүктүн төмөндөшүн күтөбүз, бирок нөлгө барабар эмес, анткени WP идеологиясы илгичтерге негизделген жана плагиндер "илгич" пайда болгондо жана "илмек" пайда болгонго чейин, маалымат базасына суроо-талаптар болушу мүмкүн. мурунтан жасалган

ой

  1. Кыска убакыттын ичинде көптөгөн суроо-талаптарды жасаган IP даректерди эсептеңиз.
  2. Сайттагы көрүүлөрдүн санын жазыңыз
  3. Хиттердин санына жараша сайтка кирүүгө бөгөт коюу
  4. .htaccess файлындагы "Башкадан баш тартуу" жазуусун колдонуу менен бөгөттөө
  5. Мен Nginx үчүн iptables жана эрежелер сыяктуу башка варианттарды эске алган жокмун, анткени мен хостинг жөнүндө жазып жатам

Идея пайда болду, андыктан аны ишке ашыруу керек, ансыз деле...

  • Маалыматтарды топтоо үчүн таблицаларды түзүү
    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 дарек биздин таблицада канчалык көп белгиленгенин көрө алабыз жана бир кружка кофе менен сүрөттү түшүнүү үчүн ал жакка 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 - сайтка кирүү мүмкүнчүлүгү жок жана маалымат базасына жүктү жаратпайт

Бирок ар бир жолу бул сыяктуу кол менен көчүрүү өтө адилеттүү иш эмес, жана андан тышкары, код автономдуу болууга багытталган.

Ар бир 30 мүнөт сайын CRON аркылуу аткарыла турган файлды кошолу:

Файл коду .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 файлына бөгөттөө эрежелерин киргизүү.
# баштоо_авто_башкаруу_тизмеси жана # авто_башкаруу_тизмеси

Эми "зыяндуу" 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де кеңейтилген версиясын алдым.

Source: www.habr.com

Комментарий кошуу