selamat hari! Dalam artikel saya akan memberitahu anda bagaimana pengguna pengehosan biasa boleh menangkap alamat IP yang menjana beban yang berlebihan di tapak dan kemudian menyekatnya menggunakan alat pengehosan, akan ada "sedikit" kod php, beberapa tangkapan skrin.
data input:
- Tapak web dibuat pada CMS WordPress
- Hosting Beget (ini bukan iklan, tetapi tangkapan skrin panel pentadbir adalah daripada penyedia pengehosan khusus ini)
- Tapak WordPress telah dilancarkan di suatu tempat pada awal tahun 2000 dan mempunyai sejumlah besar artikel dan bahan
- PHP versi 7.2
- WP mempunyai versi terkini
- Untuk beberapa waktu sekarang, laman web ini mula menjana beban yang tinggi pada MySQL mengikut data pengehosan. Setiap hari nilai ini melebihi 120% daripada norma setiap akaun
- Menurut Yandex. Tapak Metrica dikunjungi oleh 100-200 orang setiap hari
Pertama sekali, ini dilakukan:
- Jadual pangkalan data telah dibersihkan daripada sampah terkumpul
- Pemalam yang tidak diperlukan telah dilumpuhkan, bahagian kod lapuk telah dialih keluar
Pada masa yang sama, saya ingin menarik perhatian anda kepada fakta bahawa pilihan caching (pemalam caching) telah dicuba, pemerhatian telah dibuat - tetapi beban 120% dari satu tapak tidak berubah dan hanya boleh berkembang.
Apakah rupa anggaran beban pada pangkalan data pengehosan
Di bahagian atas ialah tapak yang dimaksudkan, tepat di bawah adalah tapak lain yang mempunyai cm yang sama dan lebih kurang trafik yang sama, tetapi menghasilkan kurang beban.
Analisis
- Banyak percubaan dibuat dengan pilihan caching data, pemerhatian telah dijalankan selama beberapa minggu (nasib baik, selama ini pengehosan tidak pernah menulis kepada saya bahawa saya sangat teruk dan akan terputus sambungan)
- Terdapat analisis dan carian untuk pertanyaan perlahan, kemudian struktur pangkalan data dan jenis jadual telah diubah sedikit
- Untuk analisis, kami terutamanya menggunakan AWStats terbina dalam (secara langsung, ia membantu mengira alamat IP yang paling teruk berdasarkan volum trafik
- Metrik - metrik memberikan maklumat hanya tentang orang, bukan tentang bot
- Terdapat percubaan untuk menggunakan pemalam untuk WP yang boleh menapis dan menyekat pelawat walaupun mengikut negara lokasi dan pelbagai kombinasi
- Cara yang benar-benar radikal ternyata adalah menutup tapak selama sehari dengan nota "Kami sedang diselenggara" - ini juga dilakukan menggunakan pemalam yang terkenal. Dalam kes ini, kami menjangkakan beban akan menurun, tetapi tidak kepada nilai sifar, kerana ideologi WP adalah berdasarkan cangkuk dan pemalam memulakan aktiviti mereka apabila "cangkuk" berlaku, dan sebelum "cangkuk" berlaku, permintaan kepada pangkalan data boleh sudah dibuat
Idea
- Kira alamat IP yang membuat banyak permintaan dalam tempoh yang singkat.
- Catatkan bilangan hits ke tapak
- Sekat akses ke tapak berdasarkan bilangan hits
- Sekat menggunakan entri "Tolak daripada" dalam fail .htaccess
- Saya tidak mempertimbangkan pilihan lain, seperti iptables dan peraturan untuk Nginx, kerana saya menulis tentang pengehosan
Idea telah muncul, jadi ia perlu dilaksanakan, kerana tanpa ini...
- Mencipta jadual untuk mengumpul 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;
- Mari buat fail di mana kita akan meletakkan kod tersebut. Kod akan merekodkan dalam jadual calon yang menyekat dan menyimpan sejarah untuk penyahpepijatan.
Kod fail untuk merakam alamat 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);
Intipati kod adalah untuk mendapatkan alamat IP pelawat dan menulisnya ke dalam jadual. Jika ip sudah ada dalam jadual, medan cnt akan ditambah (bilangan permintaan ke tapak)
- Sekarang perkara yang menakutkan... Sekarang mereka akan membakar saya kerana tindakan saya :)
Untuk merekodkan setiap permintaan ke tapak, kami menyambungkan kod fail ke fail WordPress utama - wp-load.php. Ya, kami menukar fail kernel dan tepat selepas pembolehubah global $wpdb sudah wujud
Jadi, sekarang kita dapat melihat berapa kerap alamat IP ini atau itu ditandakan dalam jadual kita dan dengan secawan kopi kita melihat di sana setiap 5 minit sekali untuk memahami gambar
Kemudian hanya salin IP "memudaratkan", buka fail .htaccess dan tambahkannya pada penghujung fail
Order allow,deny
Allow from all
# start_auto_deny_list
Deny from 94.242.55.248
# end_auto_deny_list
Itu sahaja, kini 94.242.55.248 - tidak mempunyai akses ke tapak dan tidak menjana beban pada pangkalan data
Tetapi setiap kali menyalin dengan tangan seperti ini bukanlah tugas yang sangat baik, dan selain itu, kod itu bertujuan untuk menjadi autonomi
Mari tambahkan fail yang akan dilaksanakan melalui CRON setiap 30 minit:
Kod fail mengubah suai .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)));
Kod fail agak mudah dan primitif dan idea utamanya adalah untuk mengambil calon untuk menyekat dan memasukkan peraturan menyekat dalam fail .htaccess antara komen
# start_auto_deny_list dan # end_auto_deny_list
Kini IP "memudaratkan" disekat dengan sendirinya dan fail .htaccess kelihatan seperti ini:
# 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
Akibatnya, selepas kod ini mula berfungsi, anda boleh melihat hasilnya dalam panel pengehosan:
PS: Bahan ini adalah milik pengarang, walaupun saya menerbitkan sebahagian daripadanya di laman web saya, saya mendapat versi yang lebih diperluaskan pada Habre.
Sumber: www.habr.com