روز خوب! در این مقاله به شما خواهم گفت که چگونه کاربران میزبانی معمولی می توانند آدرس های IP را که بار بیش از حد در سایت ایجاد می کنند را بگیرند و سپس با استفاده از ابزارهای میزبانی آنها را مسدود کنند، "کمی" کد php، چند عکس از صفحه نمایش وجود خواهد داشت.
داده های ورودی:
- وب سایت ایجاد شده بر روی CMS WordPress
- میزبانی Beget (این یک تبلیغ نیست، اما اسکرین شات های پنل مدیریت از این ارائه دهنده میزبان خاص خواهد بود)
- سایت وردپرس جایی در اوایل سال 2000 راه اندازی شد و دارای تعداد زیادی مقاله و مطالب است
- PHP نسخه 7.2
- WP آخرین نسخه را دارد
- مدتی است که سایت با توجه به داده های میزبانی شروع به تولید بار بالایی در MySQL کرده است. هر روز این مقدار بیش از 120٪ از هنجار هر حساب است
- با توجه به Yandex. سایت متریکا 100-200 نفر در روز بازدید می کنند
اول از همه این کار انجام شد:
- جداول پایگاه داده از زباله های انباشته پاکسازی شدند
- افزونههای غیر ضروری غیرفعال شدند، بخشهایی از کدهای قدیمی حذف شدند
در همان زمان، می خواهم توجه شما را به این واقعیت جلب کنم که گزینه های کش (افزونه های ذخیره سازی) آزمایش شد، مشاهداتی انجام شد - اما بار 120٪ از یک سایت بدون تغییر بود و فقط می توانست رشد کند.
بار تقریبی در پایگاه داده میزبانی چگونه به نظر می رسد
در بالا سایت مورد نظر قرار دارد، درست در زیر سایت های دیگری هستند که دارای cms یکسان و تقریباً یکسان هستند، اما بار کمتری ایجاد می کنند.
تحلیل
- تلاشهای زیادی با گزینههای ذخیرهسازی دادهها انجام شد، مشاهدات در طول چند هفته انجام شد (خوشبختانه، در این مدت هاست هرگز برای من ننوشت که من خیلی بد هستم و قطع خواهم شد)
- تجزیه و تحلیل و جستجو برای پرس و جوهای کند انجام شد، سپس ساختار پایگاه داده و نوع جدول کمی تغییر کرد
- برای تجزیه و تحلیل، ما در درجه اول از AWStats داخلی استفاده کردیم (به هر حال، به محاسبه بدترین آدرس IP بر اساس حجم ترافیک کمک کرد.
- متریک - معیار فقط اطلاعاتی در مورد افراد ارائه می دهد، نه در مورد ربات ها
- تلاشهایی برای استفاده از افزونههایی برای WP صورت گرفته است که میتواند بازدیدکنندگان را حتی بر اساس کشور محل و ترکیبهای مختلف فیلتر و مسدود کند.
- یک راه کاملاً رادیکال بسته شدن سایت به مدت یک روز با یادداشت "ما در حال تعمیر هستیم" است - این نیز با استفاده از افزونه معروف انجام شد. در این مورد، ما انتظار داریم که بار کاهش یابد، اما نه به مقادیر صفر، زیرا ایدئولوژی WP مبتنی بر قلاب ها است و پلاگین ها فعالیت خود را زمانی شروع می کنند که یک "قلاب" رخ دهد، و قبل از اینکه "قلاب" رخ دهد، درخواست ها به پایگاه داده می توانند قبلا ساخته شده است
فکر
- آدرس های IP را محاسبه کنید که در مدت زمان کوتاهی درخواست های زیادی می کنند.
- تعداد بازدیدهای سایت را ثبت کنید
- دسترسی به سایت را بر اساس تعداد بازدید مسدود کنید
- با استفاده از ورودی «رد کردن از» در فایل htaccess. مسدود کنید
- من گزینه های دیگر، مانند 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 افزایش می یابد (تعداد درخواست ها به سایت)
- حالا ترسناکه... حالا به خاطر کارهایم می سوزانند :)
برای ثبت هر درخواست به سایت، کد فایل را به فایل اصلی وردپرس - wp-load.php وصل می کنیم. بله، ما فایل هسته را تغییر می دهیم و دقیقاً بعد از اینکه متغیر جهانی $wpdb از قبل وجود داشته باشد
بنابراین، اکنون میتوانیم ببینیم چند بار این یا آن آدرس IP در جدول ما علامتگذاری شده است و با یک فنجان قهوه هر 5 دقیقه یک بار به آنجا نگاه میکنیم تا تصویر را بفهمیم.
سپس به سادگی 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 بین نظرات وارد کنید.
# 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
در نتیجه، پس از شروع به کار این کد، می توانید نتیجه را در پنل میزبانی مشاهده کنید:
PS: مطالب متعلق به نویسنده است، اگرچه من بخشی از آن را در وب سایت خود منتشر کردم، اما نسخه توسعه یافته تری را در Habre دریافت کردم.
منبع: www.habr.com