Rydym yn nodi botiau “drwg” posibl ac yn eu rhwystro gan IP

Rydym yn nodi botiau “drwg” posibl ac yn eu rhwystro gan IP

Diwrnod da! Yn yr erthygl byddaf yn dweud wrthych sut y gall defnyddwyr cynnal rheolaidd ddal cyfeiriadau IP sy'n cynhyrchu llwyth gormodol ar y wefan ac yna eu rhwystro gan ddefnyddio offer cynnal, bydd “ychydig bach” o god php, ychydig o sgrinluniau.

Data mewnbwn:

  1. Gwefan wedi'i chreu ar CMS WordPress
  2. Hosting Beget (nid hysbyseb yw hon, ond bydd sgrinluniau'r panel gweinyddol gan y darparwr cynnal penodol hwn)
  3. Lansiwyd gwefan WordPress rhywle yn gynnar yn y 2000 ac mae ganddi nifer fawr o erthyglau a deunyddiau
  4. Fersiwn PHP 7.2
  5. Mae gan WP y fersiwn diweddaraf
  6. Ers peth amser bellach, dechreuodd y wefan gynhyrchu llwyth uchel ar MySQL yn ôl y data cynnal. Bob dydd roedd y gwerth hwn yn fwy na 120% o'r norm fesul cyfrif
  7. Yn ôl Yandex. Mae 100-200 o bobl yn ymweld â safle Metrica y dydd

Yn gyntaf, gwnaed hyn:

  1. Cliriwyd tablau cronfa ddata o garbage cronedig
  2. Analluogwyd ategion diangen, tynnwyd rhannau o'r cod hen ffasiwn

Ar yr un pryd, hoffwn dynnu eich sylw at y ffaith bod opsiynau caching (plugins caching) wedi'u rhoi ar brawf, gwnaed sylwadau - ond nid oedd y llwyth o 120% o un safle wedi newid a dim ond tyfu y gallai.

Sut olwg oedd ar y llwyth bras ar gronfeydd data cynnal

Rydym yn nodi botiau “drwg” posibl ac yn eu rhwystro gan IP
Ar y brig mae'r safle dan sylw, ychydig yn is na safleoedd eraill sydd â'r un cm a thua'r un traffig, ond sy'n creu llai o lwyth.

Dadansoddi

  • Gwnaed llawer o ymdrechion gydag opsiynau storio data, gwnaed arsylwadau dros sawl wythnos (yn ffodus, yn ystod yr amser hwn ni ysgrifennodd y gwesteiwr ataf erioed fy mod mor ddrwg ac y byddwn yn cael fy datgysylltu)
  • Bu dadansoddiad a chwiliad am ymholiadau araf, yna newidiwyd strwythur y gronfa ddata a'r math o dabl ychydig
  • Ar gyfer dadansoddi, gwnaethom ddefnyddio'r AWStats adeiledig yn bennaf (gyda llaw, fe helpodd i gyfrifo'r cyfeiriad IP gwaethaf yn seiliedig ar faint y traffig
  • Metrig - mae'r metrig yn darparu gwybodaeth am bobl yn unig, nid am bots
  • Bu ymdrechion i ddefnyddio ategion ar gyfer WP a all hidlo a rhwystro ymwelwyr hyd yn oed yn ôl gwlad lleoliad a chyfuniadau amrywiol
  • Ffordd gwbl radical oedd cau'r safle am ddiwrnod gyda'r nodyn “We are under maintenance” - gwnaed hyn hefyd gan ddefnyddio'r ategyn enwog. Yn yr achos hwn, rydym yn disgwyl i'r llwyth ostwng, ond nid i werthoedd sero, gan fod ideoleg WP yn seiliedig ar fachau ac ategion yn dechrau eu gweithgaredd pan fydd “bachyn” yn digwydd, a chyn i'r “bachyn” ddigwydd, gall ceisiadau i'r gronfa ddata cael ei wneud yn barod

Syniad

  1. Cyfrifwch gyfeiriadau IP sy'n gwneud llawer o geisiadau mewn cyfnod byr o amser.
  2. Cofnodwch nifer yr ymweliadau â'r wefan
  3. Rhwystro mynediad i'r wefan yn seiliedig ar nifer yr ymweliadau
  4. Blociwch ddefnyddio'r cofnod “Gwadu rhag” yn y ffeil .htaccess
  5. Wnes i ddim ystyried opsiynau eraill, fel iptables a rheolau ar gyfer Nginx, oherwydd rwy'n ysgrifennu am westeio

Mae syniad wedi ymddangos, felly mae angen ei weithredu, oherwydd heb hyn...

  • Creu tablau i gronni 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;
    
  • Gadewch i ni greu ffeil lle byddwn yn gosod y cod. Bydd y cod yn cofnodi yn y tablau blocio ymgeiswyr ac yn cadw hanes ar gyfer dadfygio.

    Cod ffeil ar gyfer cofnodi cyfeiriadau 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);
    
    

    Hanfod y cod yw cael cyfeiriad IP yr ymwelydd a'i ysgrifennu i mewn i dabl. Os yw'r ip eisoes yn y tabl, bydd y maes cnt yn cael ei gynyddu (nifer y ceisiadau i'r wefan)

  • Nawr y peth brawychus... Nawr byddan nhw'n fy llosgi am fy ngweithredoedd :)
    I gofnodi pob cais i'r wefan, rydym yn cysylltu cod y ffeil i'r brif ffeil WordPress - wp-load.php. Ydym, rydym yn newid y ffeil cnewyllyn ac yn union ar ôl bod y newidyn byd-eang $ wpdb eisoes yn bodoli

Felly, nawr gallwn weld pa mor aml mae hwn neu'r cyfeiriad IP hwnnw wedi'i farcio yn ein bwrdd a gyda mwg o goffi rydyn ni'n edrych yno unwaith bob 5 munud i ddeall y llun

Rydym yn nodi botiau “drwg” posibl ac yn eu rhwystro gan IP

Yna copïwch yr IP “niweidiol”, agorwch y ffeil .htaccess a'i ychwanegu at ddiwedd y ffeil

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

Dyna ni, nawr 94.242.55.248 - nid oes ganddo fynediad i'r wefan ac nid yw'n cynhyrchu llwyth ar y gronfa ddata

Ond bob tro nid yw copïo â llaw fel hyn yn dasg gyfiawn iawn, ac ar wahân i hynny, bwriad y cod oedd bod yn ymreolaethol.

Gadewch i ni ychwanegu ffeil a fydd yn cael ei gweithredu trwy CRON bob 30 munud:

Cod ffeil yn addasu .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)));

Mae cod y ffeil yn eithaf syml a chyntefig a'i brif syniad yw cymryd ymgeiswyr ar gyfer blocio a nodi rheolau blocio yn y ffeil .htaccess rhwng y sylwadau
# start_auto_deny_list a # end_auto_deny_list

Nawr mae IPs “niweidiol” yn cael eu rhwystro ganddyn nhw eu hunain, ac mae'r ffeil .htaccess yn edrych rhywbeth fel hyn:

# 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

O ganlyniad, ar ôl i'r cod hwn ddechrau gweithio, gallwch weld y canlyniad yn y panel cynnal:

Rydym yn nodi botiau “drwg” posibl ac yn eu rhwystro gan IP

ON: Y deunydd yw eiddo'r awdur, er i mi gyhoeddi rhan ohono ar fy ngwefan, cefais fersiwn ehangach ar Habre.

Ffynhonnell: hab.com

Ychwanegu sylw