Vi beregner potentielle "onde" bots og blokerer dem efter IP

Vi beregner potentielle "onde" bots og blokerer dem efter IP

Goddag! I artiklen vil jeg fortælle, hvordan almindelige hostingbrugere kan fange IP-adresser, der skaber unødig belastning på hjemmesiden, og derefter blokere dem ved hjælp af hostingværktøjer; der vil være "lidt" php-kode og flere skærmbilleder.

Indledende data:

  1. Hjemmesiden er oprettet på CMS WordPress
  2. Hosting Beget (det er ikke reklame, men skærmbillederne af adminpanelet vil være fra denne hostingudbyder)
  3. WordPress-hjemmesiden blev startet omkring begyndelsen af 2000'erne og har et stort antal artikler og materialer
  4. PHP-version 7.2
  5. WP har den nyeste version
  6. I et stykke tid begyndte hjemmesiden at generere høj belastning på MySQL ifølge hostingoplysningerne. Hver dag overskred dette værdi 120% af normen for kontoen
  7. Ifølge Yandex.Metrica besøger 100-200 mennesker hjemmesiden om dagen

Først blev der gjort følgende:

  1. Renset databaserne fra ophobet affald
  2. De unødvendige plugins blev deaktiveret, og forældet kode blev fjernet

Jeg bemærker, at der blev prøvet caching-muligheder (caching-plugins), og observationer blev foretaget — men belastningen på 120% fra ét website forblev uændret og kunne kun stige.

Sådan så den omtrentlige belastning fra hostingdatabaserne ud

Vi beregner potentielle "onde" bots og blokerer dem efter IP
Øverst er hjemmesiden, der er tale om, lidt længere nede er andre hjemmesider, der bruger samme cms og har omtrent den samme trafik, men genererer mindre belastning.

Analyse

  • Der blev gjort mange forsøg med data caching-muligheder, og observationer blev foretaget i flere uger (heldigvis skrev hosting udbyderen ikke til mig, at jeg var så dårlig, at de ville lukke mig ned)
  • Der blev lavet analyser og søgt efter langsomme forespørgsler, hvorefter databasen og tabeltyperne blev lidt ændret
  • Til analysen blev den indbyggede AWStats først brugt (den hjalp faktisk med at identificere den ondskabsfulde IP-adresse baseret på trafikmængde)
  • Metrikken giver kun information om mennesker, ikke bots
  • Der blev gjort forsøg på at bruge plugins til WP, der kan filtrere og blokere besøgende baseret på deres placering og forskellige kombinationer
  • En helt radikal måde at lukke siden i et døgn med bemærkningen "Vi er under teknisk vedligeholdelse" — det blev også gjort ved hjælp af den berømte plugin. I dette tilfælde forventede vi, at belastningen ville falde, men ikke til 0, da ideologien i WP er baseret på hooks, og plugins begynder deres aktivitet, når en eller anden "hook" indtræffer, og før "hook" indtræffer, kan der allerede være lavet forespørgsler til databasen.

Idé

  1. At beregne IP-adresser, der laver mange forespørgsler på kort tid.
  2. At registrere antallet af henvendelser til siden
  3. At blokere adgangen til siden baseret på antallet af henvendelser
  4. At blokere ved hjælp af "Deny from"-posten i .htaccess-filen
  5. Andre muligheder, såsom iptables og regler til Nginx, overvejes ikke, da jeg skriver om hosting

Når ideen er der, skal den implementeres, hvordan kan man gøre uden det...

  • Vi opretter tabeller til indsamling af 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='Kandidater til blokering'
    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='Listen over allerede blokerede'
    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='Historik over alle anmodninger til debugging'
    COLLATE='utf8_general_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=1;
    
  • Lad os oprette en fil, hvor vi placerer koden. Koden vil registrere kandidater til blokering og føre historik til debugging.

    Kode til filen for at registrere IP-adresser

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

    Kernens idé er at få IP-adressen fra besøgende og registrere den i tabellen. Hvis IP'en allerede er i tabellen, vil feltet cnt (antal forespørgsler til siden) blive øget.

  • Nu er det skræmmende... Nu vil de brænde mig for mine handlinger 🙂
    For at registrere hver henvendelse til siden, tilslutter vi filens kode til hovedfilen i WordPress — wp-load.php. Ja, vi ændrer faktisk kernefilerne, og kun efter at den globale variabel $wpdb allerede eksisterer.

Så vi kan nu se, hvor ofte en bestemt IP-adresse bliver registreret i vores tabel, og med en kop kaffe kigger vi derhen hver 5. minut for at få et overblik.

Vi beregner potentielle "onde" bots og blokerer dem efter IP

Derefter er det enkelt; vi kopierede den "skadelige" IP, åbnede .htaccess-filen og tilføjede den til slutningen af filen.

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

Det er det, nu har 94.242.55.248 ikke adgang til siden og genererer ikke belastning på databasen.

Men at kopiere det manuelt hver gang er ikke det mest hensigtsmæssige, og desuden var koden tænkt som autonom.

Vi tilføjer en fil, der skal køres via CRON hver 30. minut:

Koden til filen, der ændrer .htaccess

get_results("SELECT * FROM wp_visiters_bot WHERE cnt>{$limit_cnt}");

$new_blocked = [];

$exclude_ip = [
    '87.236.16.70' // hostingadresse
];

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;
}

// Rydning af tabellen
$wpdb->query("DELETE FROM wp_visiters_bot");

//$file = '.htaccess';

$start_searche_tag = 'start_auto_deny_list';

$end_searche_tag = 'end_auto_deny_list';

$handle = @fopen($file, "r");
if ($handle) {

    $replace_string = ''; // Test til indsættelse i .htaccess-filen

    $target_content = false; // Flag for den relevante kode

    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 "Fejl: fgets() mislykkedes uventet\n";
    }
    fclose($handle);
}

// Nuværende .htaccess-fil
$content = file_get_contents($file);

$content = str_replace($replace_string, '', $content);

// Ryd alle blokeringer i .htaccess-filen
file_put_contents($file, $content);

// Indskriv nye blokeringer
$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)));

Koden til filen er ganske enkel og primitiv, og hovedideen er at tage kandidater til blokering og indsætte blokkeringsregler i .htaccess-filen mellem kommentarerne.
# start_auto_deny_list и # end_auto_deny_list

Nu blokeres de "skadelige" IP'er automatisk, og .htaccess-filen ser cirka således ud:

# 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

Som resultatet af at denne kode træder i kraft, kan man se resultatet i hostingpanelet:

Vi beregner potentielle "onde" bots og blokerer dem efter IP

PS: Materialet er originalt, selvom en del af det er offentliggjort på min egen hjemmeside, er der en mere udvidet version på Habre.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster