
Բարի օր! Այս հոդվածում կկիսեմ, թե ինչպես է հնարավոր սովորական հոստինգի օգտատերերին հայտնաբերել IP հասցեները, որոնք ստեղծում են ավելորդ нагрузка կայքի վրա, և ապա արգելափակել դրանք հոստինգի միջոցների միջոցով, կլինի «մ trochę» php կոդ, մի քանի սկրինշոթ:
Ներդրած տվյալներ:
- Կայքը ստեղծվել է CMS WordPress-ի վրա
- Հոստինգ Բեգետ (այսինքն՝ սա չի գովազդ, բայց адмինկայի սկրինշոթերը կլինեն հենց այդ հոստինգի մատակարարը)
- WordPress կայքը գործարկվել է 2000-ների սկզբում և ունի մեծ քանակությամբ հոդվածներ և նյութեր
- PHP տարբերակը 7.2
- WP-ն ունի վերջին տարբերակը
- Մի քանի ժամանակ առաջ կայքը սկսել է բարձր нагрузка ստեղծել MySQL-ում ըստ հոստինգի տվյալների: Արդյունքում, ամեն օր այս ցուցանիշը գերազանցում էր 120%-ը նորմայից
- Յանդեքս Մետրիկայի տվյալներով կայքն այցելում է 100-200 մարդ օրական
Առաջին հերթին կատարվել է.
- Մաքրվել են DB սեղանների կուտակված աղբը
- Հանվել են անպետք պլագինները,Remove outdated code snippets
Այս ընթացքում նշում եմ, փորձվել են кешավորման տարբերակները (կաշեի պլագիններ), անցկացված են դիտարկումներ՝ սակայն 120%-ը մեկ կայքից բացարձակապես չէր փոխվում և միայն կարող էր աճել:
Ինչպես էլ որ թվանշաններն էին գումարային բազաների нагрузка

Առաջին տեղը զբաղեցնում է այն կայքը, որը քննարկում է, հատկապես մյուս կայքերը, որոնք ունեն նույն cms-ը և մոտավորապես նույն այցելուները, բայց ավելի քիչ нагрузка են ստեղծում:
Վերլուծություն
- Մեծ թվով փորձեր եղել են տվյալների кешավորման տարբերակներով, դիտարկումներ են անցկացվել մի քանի շաբաթվա ընթացքում (լավ է, որ այդ ընթացքում հոստինգը ինձ ոչ մի անգամ չի գրել որ ես վատն եմ և ինձ արգելափակում են)
- Կատարվել է ուշ запросների վերլուծություն և որոնում, ապա մի փոքր փոխվել է DB կառուցվածքը և սեղանների տեսակները
- Վերլուծության համար առաջին հերթին օգտագործվել է դյուրակիր AWStats (իսկապես թե դա օգնեց պարզել ամենաբարի IP հասցեն ըստ տրաֆիկի ծավալի)
- Մետრիկան՝ մետրիկան տալիս է տեղեկատվություն միայն մարդկանց մասին, բայց ոչ բոտերի
- Մուրացկուն վերլուծությունը փորձվել են WP պլագինները, որոնք կարող են ֆիլտրել և արգելափակել այցելուներին անգամ ըստ գտնվելու երկրի և տարբեր կոմբինացիաների
- Շատ ռադիկալ միջոցը կայքը փակել էր մեկ օրով `«Մենք տեխնիկական սպասարկման մեջ ենք» նշումով ՝ սա ևս կատարվել է հայտնի պլագինի միջոցով: Այս դեպքում, нагрузка տարին 0-0 աստիճաններին, քանի որ WP-ի գաղափարաբանը հիմնված է հուկերի վրա, և պլագիններն սկսում են իրենց գործունեությունը երբևէ ներկայացնելով որևէ «հուկ», իսկ մինչև «հուկ» հասնելը կարող են կատարվել запросներ DB-ում:
Ուղղություն
- Հաշվարկել IP հասցեները, որոնք կատարում են բազմաթիվ запросներ կարճ ժամանակահատվածում:
- Գրանցել կայքին այցերի քանակը
- Հիմք ընդունելով այցերի քանակը արգելափակել մուտքը կայք
- Արգելափակել «Deny from» գրառման միջոցով .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='ԻAlready blocked candidates' 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-ը, բացեցինք .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-ը չունի մուտք դեպի կայքը և չի ստեղծում բեռնման բազան:
Բայց յուրաքանչյուրը ստորագրությամբ այն ձեռք ձեռքի աշխատելն այնքան ճիշտ չէ, այն էլ կոդը նախատեսվում էր որպես ինքնօգտագործելի:
Ավելացնենք ֆայլ, որը կիրականացվի CRON-ով յուրաքանչյուր 30 րոպե:
Կոդը ֆայլը, որը փոփոխում է .htaccess
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 '';print_r($new_blocked);echo '
';$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
Արդյունքում, այսպիսի կոդի կիրառման սկսումից հետո կարելի է տեսնել արդյունքը հոստինգի վահանակում:

ՊՍ: Մատերիալը հեղինակային է, չնայած որ դրա մի մասը ես արդեն հրապարակել եմ իմ կայքում, սակայն Habre-ում ստացվեց ավելի լայնացված տարբերակ:
Ընտանիք: habr.com
