Calculamos posibles robots "malvados" y los bloqueamos por IP



Buen dia En el artículo, le diré cómo es posible que los usuarios de hosting ordinarios capturen direcciones IP que generan una carga excesiva en el sitio y luego las bloqueen con herramientas de hosting, habrá "un pequeño" código php, algunas capturas de pantalla.

Datos de entrada:

  1. Sitio web creado en CMS WordPress
  2. Hosting Beget (esto no es un anuncio, pero las capturas de pantalla del panel de administración serán de este proveedor de hosting)
  3. El sitio de WordPress se lanzó en algún lugar a principios de 2000 y tiene una gran cantidad de artículos y materiales.
  4. PHP Versión 7.2
  5. WP tiene la última versión
  6. Desde hace algún tiempo, el sitio comenzó a generar una gran carga en MySQL de acuerdo con el alojamiento. Todos los días, este valor superó el 120% de la norma por cuenta
  7. De acuerdo con Yandex. El sitio métrico es visitado por 100-200 personas por día.

En primer lugar, se hizo:

  1. Las bases de datos se limpian de basura acumulada
  2. Los complementos innecesarios están deshabilitados, las secciones de código obsoleto se eliminan

Al mismo tiempo, llamo la atención sobre las opciones de almacenamiento en caché (complementos de almacenamiento en caché), realizamos observaciones, pero la carga del 120% de un sitio no cambió y solo pudo crecer.

Cómo se veía la carga aproximada en las bases de datos de hosting


En la parte superior está el sitio en cuestión, justo debajo de otros sitios que tienen los mismos cms y casi el mismo tráfico, pero crean menos carga.

Análisis

  • Se hicieron muchos intentos con opciones de almacenamiento en caché de datos, se realizaron observaciones durante varias semanas (el beneficio del alojamiento durante este tiempo nunca he escrito que soy tan malo y me desconectará)
  • Hubo un análisis y búsqueda de consultas lentas, luego la estructura de la base de datos y el tipo de tabla cambiaron ligeramente
  • Para el análisis, el AWStats incorporado se usó principalmente (por cierto, ayudó a calcular la dirección IP más malvada por volumen de tráfico
  • Métrica: la métrica brinda información solo sobre personas, no sobre bots
  • Hubo intentos de usar complementos para WP, que pueden filtrar y bloquear visitantes incluso por país de ubicación y por varias combinaciones
  • Una forma completamente radical resultó ser cerrar el sitio por un día con la marca "Estamos en mantenimiento", esto también se hizo usando el famoso complemento. En este caso, esperamos que la carga caiga, pero no a valores de 0 a la izquierda, ya que la ideología de WP se basa en enlaces y los complementos comienzan su actividad cuando se produce algún tipo de "enlace", y antes de que ocurra el "enlace", las consultas a la base de datos ya pueden realizarse

Idea

  1. Calcule las direcciones IP que realizan muchas solicitudes en un corto período de tiempo.
  2. Fijar la cantidad de visitas al sitio
  3. Según la cantidad de visitas que bloquean el acceso al sitio
  4. Bloquee utilizando la entrada "Denegar de" en el archivo .htaccess
  5. Otras opciones, como iptables y reglas para Nginx sin tener en cuenta, porque escribo sobre hosting

Surgió una idea, por lo que debe implementarla, ya que sin ella ...

  • Creamos tablas para la acumulación de datos.

    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; 
  • Crea un archivo en el que colocaremos el código. El código se escribirá en la tabla de candidatos para el bloqueo y mantendrá un historial de depuración.

    Código de archivo para registrar direcciones 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); 


    La esencia del código es obtener la dirección IP del visitante y escribirla en la tabla. Si ip ya está en la tabla, se aumentará el campo cnt (la cantidad de solicitudes al sitio)
  • Ahora da miedo ... Ahora me van a quemar por mis acciones :)
    Para registrar cada llamada al sitio, incluimos el código del archivo en el archivo principal de WordPress: wp-load.php. Sí, modificamos el archivo del núcleo precisamente después de que la variable global $ wpdb ya exista

Entonces, ahora podemos ver con qué frecuencia esta o esa dirección IP se anota en nuestra tabla y con una taza de café miramos allí cada 5 minutos para comprender la imagen



Luego simplemente copie la IP "dañina", abra el archivo .htaccess y agréguelo al final del archivo

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

Todo, ahora 94.242.55.248: no tiene acceso al sitio y no genera una carga en la base de datos

Pero cada vez, copiar con sus propias manos no es una tarea muy justa, y además, el código fue concebido como autónomo

Agregue un archivo que CRON ejecutará cada 30 minutos:

Código de archivo que modifica .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))); 


El código del archivo es bastante simple y primitivo y su idea principal es tomar candidatos para el bloqueo e ingresar las reglas de bloqueo en el archivo .htaccess entre comentarios
# start_auto_deny_list y # end_auto_deny_list

Ahora las IP "dañinas" están bloqueadas por sí mismas, y el archivo .htaccess se parece a esto:

 # 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 

Como resultado, después del comienzo de la acción de dicho código, puede ver el resultado en el panel de alojamiento:



PD: El material tiene copyright, aunque publiqué parte de él en mi sitio, pero en Habre se obtuvo una versión más ampliada.

Source: https://habr.com/ru/post/473030/


All Articles