Это новая функция в плагине WatchMan-Site7 (v.3.0.3). Я хочу создать некое интеллектуальное ядро, которое анализировало каждый вид и характер атаки на сайт и принимало решение по противодействию этим атакам. Естественно – атаки со временем меняются, совершенствуются. Следовательно – будет изменятся и анализатор атак (Attack analyzer).
Перед написанием этой статьи я подумал: а стоит ли описывать методы противодействия хакерам, “помогая” тем самым им совершенствовать свои атаки. Подумав не раз, я все-таки решил написать. И вот почему:
1. Противодействие анти-хакеров и хакеров – будет всегда. Каждая сторона совершенствует свои методы. Это похоже на бег по вертикали. Пока кто-то первым не устанет.
2. Каждый хакер, как бы он этого не хотел – оставляет следы. Задача анти-хакера – найти их и как можно больше.
3. Код плагина – открытый (Open source). Поэтому, при желании злоумышленник может изучить методы противодействия ему всегда.
Еще до создания Attack analyzer в плагине WatchMan-Site7 был написан код, считывающий информацию о посетителе сайта:
/** * Forms IP data from global variables. * * @return string data of IP visitor. */ private function wms7_get_user_ip() { // We get the headers or use the global SERVER. if ( function_exists( 'apache_request_headers' ) ) { $headers = apache_request_headers(); $list = '---Apache request headers-------------<br>'; foreach ( $headers as $header => $value ) { $list = $list . $header . ': ' . $value . '<br>'; } } else { $headers = filter_input_array( INPUT_SERVER, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ); $list = '---$_SERVER request headers-----------<br>'; foreach ( $headers as $header => $value ) { if ( substr( $header, 0, 5 ) === 'HTTP_' ) { $header = substr( $header, 5 ); $header = str_replace( '_', ' ', $header ); $header = strtolower( $header ); $header = ucwords( $header ); $header = str_replace( ' ', '-', $header ); $list = $list . $header . ': ' . $value . '<br>'; } } } $the_ip = ''; // We get the redirected IP-address, if it exists. $_x_forwarded_for = filter_input( INPUT_SERVER, 'X-Forwarded-For', FILTER_SANITIZE_STRING ); if ( $_x_forwarded_for ) { $the_ip .= 'X-Forwarded-For = ' . $_x_forwarded_for . '<br>'; } $_http_x_forwarded_for = filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED_FOR', FILTER_SANITIZE_STRING ); if ( $_http_x_forwarded_for ) { $the_ip .= 'HTTP_X_FORWARDED_FOR = ' . $_http_x_forwarded_for . '<br>'; } $_http_x_forwarded = filter_input( INPUT_SERVER, 'HTTP_X_FORWARDED', FILTER_SANITIZE_STRING ); if ( $_http_x_forwarded ) { $the_ip .= 'HTTP_X_FORWARDED = ' . $_http_x_forwarded . '<br>'; } $http_x_cluster_client_ip = filter_input( INPUT_SERVER, 'HTTP_X_CLUSTER_CLIENT_IP', FILTER_SANITIZE_STRING ); if ( $http_x_cluster_client_ip ) { $the_ip .= 'HTTP_X_CLUSTER_CLIENT_IP = ' . $http_x_cluster_client_ip . '<br>'; } $_http_forwarded_for = filter_input( INPUT_SERVER, 'HTTP_FORWARDED_FOR', FILTER_SANITIZE_STRING ); if ( $_http_forwarded_for ) { $the_ip .= 'HTTP_FORWARDED_FOR = ' . $_http_forwarded_for . '<br>'; } $_http_forwarded = filter_input( INPUT_SERVER, 'HTTP_FORWARDED', FILTER_SANITIZE_STRING ); if ( $_http_forwarded ) { $the_ip .= 'HTTP_FORWARDED = ' . $_http_forwarded . '<br>'; } $_http_client_ip = filter_input( INPUT_SERVER, 'HTTP_CLIENT_IP', FILTER_SANITIZE_STRING ); if ( $_http_client_ip ) { $the_ip .= 'HTTP_CLIENT_IP = ' . $_http_client_ip . '<br>'; } $_remote_addr = filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING ); if ( $_remote_addr ) { $the_ip .= 'REMOTE_ADDR = ' . $_remote_addr; } return $list . '---' . $the_ip . '---'; }
Результат работы этого кода:
---Apache request headers------------- Host: adminkov.bcr.by User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://adminkov.bcr.by/still/ Cookie: wordpress_test_cookie=WP+Cookie+check; wordpress_logged_in_3ccfd98e86faaa1abd5f45846aa6bc93= user1%7C1541751799%7C6nLDA3iptBYHTekh0n47KYuzjPiEIcrsYxqgh3dmtCO%7Caec6e0f4028811976212e4b7cdc2cb465ebc125e8b50ce1cc8eb05d683cd3e37 Connection: keep-alive ---REMOTE_ADDR = 93.115.86.4--- ---Information about the Cookie visitor--- wordpress_test_cookie=WP Cookie check wordpress_logged_in_3ccfd98e86faaa1abd5f45846aa6bc93= user1|1541751799|6nLDA3iptBYHTekh0n47KYuzjPiEIcrsYxqgh3dmtCO|aec6e0f4028811976212e4b7cdc2cb465ebc125e8b50ce1cc8eb05d683cd3e37
Помимо этого – плагин WatchMan-Site7 собирает данные о геолокации посетителя сайта и его провайдера.
🙂 Возвращаюсь к описанию Attack analyzer.
1. Замечено, что злоумышленник готовя атаку Brute force, сначала сканирует перечень зарегистрированных пользователей с ролью: author или administrator. Иногда, быает, что это “чудо в штанишках” производит это действие с одного IP. В этом случае, вероятность поймать истинный адрес злоумышленника (а не прокси) вырастает многократно.
2. Насколько мне известно: разработчики WordPress готовы отказаться от использования xmlrpc.php и создают нечто другое в архитектуре этой CMS. Предвидя это я уже ввел в Attack analyzer – блокирование IP посетителей, которые обращаются к этому файлу. Более того, за три года изучения CMS WordPress я не видел где-либо активного использования xmlrpc.php Хлопот от него много, а пользы мало.
3. При первой же попытке залогиниться под именем администратора или автора – произойдет блокировка IP посетителя.
Важно: чтобы не забанить самого себя (администратора, автора) прежде всего пропишите IP адреса, исключенные для регистрации посещения (п.2 Do not register visits for:) в настройках плагина !
Ниже приводится код анализатора атак (Attack analyzer). Он еще мал, но со временем вырастет.
<?php /** * Description: Analyzes attacks targeting a website. * * PHP version 7.4 * * @category wms7-attack-analyzer.php * @package WatchMan-Site7 * @author Oleg Klenitskiy <klenitskiy.oleg@mail.ru> * @version 4.0.0 * @license GPLv2 or later */ if ( ! defined( "ABSPATH" ) ) { exit(); } /** * Block a visitor. * * @param string $ban_notes Ban notes. * @param boolean $ban_user_agent Ban user agent. */ function wms7_block_visitor( $ban_notes, $ban_user_agent ) { // baned user ip. $arr = array( "ban_start_date" => date( "Y-m-d" ), "ban_end_date" => date( "Y-m-d", ( strtotime( "next week", strtotime( date( "Y-m-d" ) ) ) ) ), "ban_message" => "Attack analyzer", "ban_notes" => $ban_notes, "ban_login" => false, "ban_user_agent" => $ban_user_agent, ); $black_list = wp_json_encode( $arr ); return $black_list; } /** * Analyzes the nature of the site visit. * * @param string $_log Login. * @param string $page_visit Page visit. * @param string $_http_user_agent User agent. * @param string $user_ip User IP. */ function wms7_attack_analyzer( $_log, $page_visit, $_http_user_agent, $user_ip ) { $_http_user_agent = filter_input( INPUT_SERVER, "HTTP_USER_AGENT", FILTER_SANITIZE_STRING ); $black_list = ""; $ban_user_agent = false; if ( "" == get_option( "user_agent_attack" ) ) { update_option( "user_agent_attack", $_http_user_agent ); update_option( "user_ip_attack", $user_ip ); } else { if ( get_option( "user_agent_attack" ) == $_http_user_agent && get_option( "user_ip_attack" ) !== $user_ip ) { $ban_user_agent = true; // Delete item from options. update_option( "user_agent_attack", "" ); update_option( "user_ip_attack", "" ); } else { $ban_user_agent = false; update_option( "user_agent_attack", $_http_user_agent ); update_option( "user_ip_attack", $user_ip ); } } // Если пустой User Agent - баним на 1 неделю. if ( "" == trim( $_http_user_agent ) ) { // Insert to black_list. $black_list = wms7_block_visitor( "Empty User Agent", $ban_user_agent ); // Insert to htaccess. wms7_agent_ins_to_file( "" ); wms7_ip_ins_to_file( $user_ip ); update_option( "user_agent_attack", "" ); return $black_list; } // Если доступ через xmlrpc - баним на 1 неделю. if ( strpos( $page_visit, "xmlrpc" ) ) { // Insert to black_list. $black_list = wms7_block_visitor( "Access via xmlrpc", $ban_user_agent ); // Insert to htaccess. wms7_ip_ins_to_file( $user_ip ); // Insert user_agent into .htaccess. if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) { wms7_agent_ins_to_file( $_http_user_agent ); } return $black_list; } // Если Brute force - баним IP. if ( $_log ) { $user_info = get_user_by( "login", $_log ); if ( $user_info ) { $user_role = array_shift( $user_info->roles ); if ( ( "administrator" == $user_role ) || ( "author" == $user_role ) ) { // Insert to black_list. $black_list = wms7_block_visitor( "Brute force: " . $user_role, $ban_user_agent ); // Insert to htaccess. wms7_ip_ins_to_file( $user_ip ); // Insert user_agent into .htaccess. if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) { wms7_agent_ins_to_file( $_http_user_agent ); } return $black_list; } } } // Если Сканирование структуры сайта - баним IP. if ( strpos( $page_visit, "wp-content" ) || strpos( $page_visit, "wp-includes" ) ) { // Insert to black_list. $black_list = wms7_block_visitor( "Scan the site structure", $ban_user_agent ); // Insert to htaccess. wms7_ip_ins_to_file( $user_ip ); // Insert user_agent into .htaccess. if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) { wms7_agent_ins_to_file( $_http_user_agent ); } return $black_list; } // Если Сканирование авторов сайта - баним IP. if ( strpos( $page_visit, "author" ) || strpos( $page_visit, "/wp-json/wp/v2/users" ) ) { // Insert to black_list. $black_list = wms7_block_visitor( "Scan authors site", $ban_user_agent ); // Insert to htaccess. wms7_ip_ins_to_file( $user_ip ); // Insert user_agent into .htaccess. if ( $ban_user_agent && "" !== trim( $_http_user_agent ) ) { wms7_agent_ins_to_file( $_http_user_agent ); } return $black_list; } return $black_list; }
p.s.: Даже, если Вы забанили самого себя (любимого), то можете зайдя на свой хостинг по FTP, убрать блокирующую запись из htaccess. Но нужно это сделать достаточно быстро, т.к. работает крон-событие: wms7_htaccess. Это событие срабатывает 1 раз в 1 час. За этот промежуток времени нужно почистить поле Black List в нужной строке таблицы посещений основного экрана плагина WatchMan-Site7.
p.p.s: Крон-событие wms7_htaccess занимается тем, что приводит в соответствие записи о блокировках IP с параметрами блокировок (начало и окончание блокировки IP). В данном случае: если строка блокировки будет удалена из htaccess в ручную, то в течении 1 часа она будет восстановлена, если дата окончания блокировки еще не наступила.