+7 (495) 7 8888 03 Личный кабинет
Защита сайта от парсинга и ботов
#парсинг #защита #боты

Защита сайта от парсинга и ботов

Интенсивные запросы сильно нагружают сервера и транспортные каналы, существенно замедляя работу сайта. С помощью сканирования злоумышленники копируют содержимое сайтов и выявляют слабые стороны в их защите, нанося при этом значительный ущерб. Кроме того, запросы к сайту, производящиеся в процессе сканирования, также отрицательно влияют на производительность. Чаще всего проблема медленной работы сайтов касается крупных порталов с высокой посещаемостью. Но она может коснуться и небольших сайтов, так как даже при малой посещаемости сайт может подвергаться высокой нагрузке. Высокая нагрузка создается различными роботами, постоянно сканирующими сайты. При этом работа сайта может сильно замедлиться, или он вообще может оказаться недоступным.

Сканирование сайта производится программами, сторонними сайтами или вручную. При этом создается большое количество запросов в короткий промежуток времени. Сканирование сайта чаще всего используют для поиска в нем уязвимостей или копирования содержимого сайта.

Достаточно эффективной мерой защиты сайта от сканирования будет разграничение прав доступа к ресурсам сайта. Информацию о структуре сайта поможет скрыть модуль apache mod_rewrite изменяющий ссылки. А сделать неэффективным сканирование ссылок и, одновременно, снизить нагрузку поможет установка временной задержки между частыми запросами исходящими от одного пользователя. Для поддержания эффективной защиты от сканирования и хаотичных интенсивных запросов необходим регулярный аудит вэб-ресурсов.

Хаотичные интенсивные запросы – это случайные или злонамеренные многочисленные запросы в короткий промежуток времени на страницы сайта со стороны пользователей или роботов. К примеру случайных интенсивных запросов относится частое обновление страницы. К злонамеренным многочисленным запросам относится спам на страницы сайта со стороны пользователей или DoS атаки. К хаотичным интенсивным запросам так же относится способ подбора паролей методом перебора. Подобрать пароль можно как вручную, так и при помощи специальных программ. Вручную пароль подбирается лишь в тех случаях, когда известны его возможные варианты. В других случаях используются специальные программы, осуществляющие автоматический подбор пары логина и пароля, т.е. программы для брутфорса.

К эффективным методам защиты сайта от хаотичных интенсивных запросов относятся: установка временной задержки между запросами в определенный промежуток времени, создание черного и белого списков, установка для поисковых систем временной задержки между запросами страниц сайта в файле robots.txt и установка периода обновления страниц в файле sitemap.xml.

Решено было реализовать один из методов по защите сайта от сканирования и хаотичных интенсивных запросов, который заключается в подсчете количества запросов в определенный промежуток времени и установке временной задержки при превышении установленного порога. В частности этот метод делает неэффективным или даже бесполезным способ взлома пароля путём перебора, потому что затраченное на перебор время будет слишком велико. Готовый php скрипт под капотом.

Данные о реализуемом php-скрипте


В настоящее время на практике используются различные подходы к защите любой компьютерной информации, в том числе и информации, располагаемой на Интернет-ресурсе. Данные подходы могут быть определены следующими характеристиками:
— наличием формализованных требований, как к набору, так и к параметрам всех механизмов защиты, которые регламентируются большинством современных требований к обеспечению общей компьютерной безопасности (иначе говоря, требованиями, определяющими, что именно должно быть предусмотрено разработчиками);
— наличием реальных механизмов защиты, которые реализуются в процессе защиты любой компьютерной информации. К таким механизмам защиты, прежде всего, относя встроенные в операционную систему средства защиты, по той простой причине, что в большинстве своем используемые на веб-сервере скрипты пользуются встроенными в операционную систему механизмами защиты или же наследуют используемые в них методы. Именно на базе этих механизмов и используемых в них методов определяется общий уровень защиты всего веб-сервера;
— существующей статистикой различных угроз безопасности компьютерной информации. В частности, это данные об уже осуществленных успешных атаках на какие-либо информационные ресурсы. Ведение данной статистики призвано помочь определить, насколько эффективны предпринятые меры защиты, а также дать оценку уровню выдвигаемых требований к созданию защиты на веб-сервере.

Как уже упоминалось, наиболее эффективным методом для противодействия сканированию сайта, а также всем видам хаотичных интенсивных запросов, является установка некоторой временной задержки между запросами, исходящими от одного и того же пользователя. При идентификации пользователя основной упор следует делать на его IP-адрес, по той причине, что файлы cookie могут быть легко удалены. Конечно же, IP-адрес пользователя также может быть изменен, к примеру, при помощи прокси-сервера или же с помощью переподключения, в случае, если IP-адрес у пользователя динамический, правда, такая операция может занять довольно много времени, что в свою очередь сведет на нет все старания злоумышленника.

Данный метод защиты сайта следует реализовать путем написания php-скрипта. Использование такого рода скрипта поможет защитить содержимое сайта от сканирования проводимого при помощи программ-краулеров и, одновременно, поможет существенно замедлить проведение сканирования сайта «вручную». Кроме того, использование подобного скрипта обеспечит прекрасную защищенность абсолютно всех страниц сайта от различных видов хаотичных интенсивных запросов, что в свою очередь даст возможность снизить нагрузку на оборудование веб-сервера.

Разрабатываемый скрипт должен иметь возможность настройки. В частности необходимо заранее предусмотреть возможность изменения части параметров скрипта. Иначе говоря, в скрипте должно быть:
— наличие возможности настройки времени блокировки IP-адреса пользователя;
— наличие возможности задать интервал времени, в который будет проверяться активность пользователя, иначе говоря, время, в течение которого будет вестись учет количества запросов, поступивших от одного определенного пользователя;
— наличие возможности установки количества запросов, которые один пользователь сможет отправить на страницы сайта в течение заданного временного интервала;
— наличие возможности создания списка «всегда разрешенных IP-адресов». IP-адреса, внесенные в данный список, никогда не будут заблокированы;
— наличие возможности создания списка «всегда запрещенных IP-адресов», т.е. скрипт всегда будет блокировать IP-адреса, которые внесены в данный список.

Преимуществами создания и использования подобного php-скрипта можно считать:
— существенное снижение количества запросов, отправляемых к серверу баз данных;
— существенную экономию входящего и исходящего трафика на веб-сервере;
— наличие удобной и гибкой настройки наиболее важных параметров работы скрипта;
— возможность существенного снижения нагрузки на веб-сервер со стороны пользователей;
— копирование всей информации, размещенной на сайте, будет сильно затруднено или даже невозможно в случае, если страниц на данном ресурсе достаточно много.

В процессе разработки скрипта важным моментом является выбор способа хранения получаемой информации. В нашем случае, это IP-адреса текущих пользователей. Данная информация может храниться либо в базе данных, либо на жестком диске. Для того чтоб ускорить работу разрабатываемого скрипта, а также сделать его более устойчивым, для хранения IP-адресов текущих пользователей мы будем использовать директории кэширования.

В одну из таких директорий скрипт будет помещать на хранение IP-адреса активных, на данный момент пользователей, эта директория будет носить название active. А в другую директорию мы будем вносить файлы, название которых будет включать IP-адреса временно заблокированных пользователей (директория block).

Кроме IP-адреса, в процессе работы скрипта, также понадобиться информация об активности пользователя. Для этого в название файла, содержащего IP-адрес пользователя, мы также будем вносить точное системное время, когда он проявил «первую», в заданный промежуток времени, активность, т.е. первый раз за определенный (заранее установленный) промежуток времени отправил запрос к странице сайта. В случае, если пользователь в заданный интервал времени превысил заранее определенное в скрипте количество отправленных запросов к страницам сайта, скрипт удалит файл, содержащий его IP-адрес из директории активных пользователей. После чего запишет новый файл (название которого будет содержать IP-адрес только что заблокированного пользователя) в директорию, содержащую заблокированные IP-адреса. Таким образом, в директориях кэширования (active и block) будут временно сохраняться файлы с такими названиями как: 127.0.0.1_1302615293, 195.80.91.151_1302615389, 95.30.17.60_1302615457, 77.39.54.104_ 1302615504 и тому подобные.

В имени файла, до нижнего слеша, будет содержаться IP-адрес активного пользователя, а после нижнего слеша в имя файла будет вноситься точное системное время, в которое он проявил активность (т.е. отправил запрос к страницам ресурса или же был заблокирован).

Отдельно следует отметить тот момент, что для директорий кэширования, т.е. папок active и block, обязательно нужно выставить права доступа владельца файла или 777. Иначе говоря, атрибуты данных папок, указанные на сервере, должны давать скрипту право на запись, право на чтение, а также право на выполнение. Права доступа 777 обязательно должны быть установлены для всех групп пользователей.

К тому же следует предусмотреть отдельное исключение на случай, если администратор сайта этого не сделает. Ведь в подобной ситуации работа скрипта будет невозможна, а значит, защита сайта от сканирования и хаотичных интенсивных запросов окажется, как минимум, несостоятельной. Иначе говоря, в процессе работы скрипта обязательно должно проверяться наличие или же отсутствие возможности произведения чтения, а также записи в какую-либо из директорий кэширования.

Информацию о текущих пользователях (в частности, об их IP-адресах) мы будем брать из суперглобального массива $_SERVER[]. Данный массив создается веб-сервером. В нем содержатся значения разнообразных переменных окружения. Для работы с IP-адресами пользователей нам понадобиться использовать такие переменные окружения, содержащиеся в суперглобальном массиве $_SERVER[]:
— $_SERVER['HTTP_X_FORWARDED_FOR'];
— $_SERVER['HTTP_CLIENT_IP'];
— $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
— $_SERVER['HTTP_PROXY_USER'];
— $_SERVER['REMOTE_ADDR'].

Переменная окружения $_SERVER['HTTP_X_FORWARDED_FOR'] дает нам возможность определить IP-адрес клиента, если он использует для работы прокси-сервер. Переменная окружения $_SERVER['HTTP_CLIENT_IP'] дает возможность получить IP-адрес клиента, если он не использует прокси-сервер, для работы в Интернете. Переменная окружения $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] дает возможность получить IP-адрес клиента, в случае, если на сайте не используется криптографический протокол SSL, обеспечивающий безопасное соединение между сервером и клиентом. Переменная окружения $_SERVER['HTTP_PROXY_USER'] дает возможность определить IP-адрес клиента, который использует в работе прокси-сервер.

Переменная окружения $_SERVER['REMOTE_ADDR'] дает возможность получить IP-адрес удаленного пользователя. Во время тестирования на локальной машине данный IP-адрес будет равен 127.0.0.1. В то же время в сети данная переменная вернет либо IP-адрес клиента, либо IP-адрес последнего используемого пользователем прокси-сервера (при помощи которого данный клиент попал на веб-сервер). Таким образом, используя одновременно множество различных переменных окружения из массива $_SERVER[] (все используемые переменные приведены выше), у нас будет возможность определить реальный IP-адрес пользователя, даже в том случае, если он попытается его «замаскировать» при помощи какого-либо прокси-сервера.

Для устойчивой работы скрипта на любой из страниц сайта, вне зависимости от ее уровня вложенности, будем использовать возможность приведения к абсолютному виду путей к директориям кэширования (active и block). Использование такого подхода даст нам возможность запускать скрипт с любой страницы сайта и при этом не опасаться того, что изначально указанные в скрипте относительные пути к директориям кэширования на какой-то из страниц окажутся неверными.

Как уже упоминалось, разрабатываемый скрипт должен иметь возможность настройки. В частности необходимо заранее предусмотреть возможность изменения части параметров скрипта (времени блокировки IP-адреса пользователя, интервала времени, за который будет учитываться количество запросов отправляемых к страницам ресурса, а также количества разрешенных запросов в данный интервал времени). Данные параметры изначально в скрипте будут задаваться при помощи констант.

В частности, подобными константами в скрипте будут указаны такие пара-метры:
— время блокировки IP-адреса пользователя указываемое в секундах (const blockSeconds);
— интервал времени, в который будут учитываться запросы от одного пользователя к страницам сайта. Данный интервал также будет указываться в секундах (const intervalSeconds);
— количество запросов к страницам веб-сайта, которые сможет отправить один пользователь за заданный временной промежуток (const intervalTimes).
Отдельно в скрипте следует определить такие массива, содержащие строчные данные:
— массив значений тех IP-адресов, которые внесены в «список всегда разрешенных IP-адресов» (объявление массива public static $alwaysActive = array(‘’));
— массив значений тех IP-адресов, которые внесены в «список всегда запрещенных IP-адресов» (объявление массива public static $alwaysBlock = array(‘’)).
Для правильной работы скрипта, а также для его отладки необходимо предусмотреть наличие в скрипте нескольких флагов. Отметим, что использование подобных флагов также поможет в процессе защиты содержимого сайта от сканирования и различных хаотичных интенсивных запросов. К таким флагам можно отнести:
— флаг возможности подключения всегда активных пользователей (const isAlwaysActive);
— флаг возможности подключения всегда заблокированных пользователей (const isAlwaysBlock).
Разработанный скрипт содержит один класс BotBlockIp. Данный класс включает такие методы:
— checkIp(). Данный метод реализовывает возможность произведения проверки IP-адреса пользователя на его блокировку или же на активность. При этом пропускаются IP-адреса, внесенные в список «всегда разрешенных IP-адресов», а IP-адреса внесенные в список «всегда запрещенных IP-адресов» наоборот блокируются. В случае, если пользовательский IP-адрес не найден в массиве возможных IP-адресов – скрипт создаст идентификатор нового активного IP-адреса;
— _getIp(). Данный метод дает возможность получить текущий IP-адрес пользователя, выбираемый из всех возможных IP-адресов (фильтрация производиться до выявления нужного IP-адреса клиента). Метод возвращает полученный IP-адрес.

В конечном счете разработанный скрипт может считаться эффективным инструментом, который поможет оказывать противодействие процессу сканирования сайта, а также станет мерой пресечения для всех видов хаотичных интенсивных запросов. В разработанном скрипте имеется установка некоторой временной задержки между запросами, исходящими от одного и того же пользователя. При идентификации пользователя основной упор делается на его IP-адрес. Причина этого проста – дело в том, что файлы cookie могут быть легко удалены с компьютера злоумышленника, а значит строить защиту ресурса с их использованием нельзя.

Конечно же, IP-адрес пользователя также может быть изменен, к примеру, при помощи прокси-сервера. Для того чтоб исключить подобную возможность для злоумышленника, в скрипте используются переменные окружения, которые в свою очередь помогают выявить реальный IP-адрес пользователя. Именно этот IP-адрес, в случае превышения пользователем установленного лимита запросов к страницам сайта в определенный промежуток времени, окажется заблокированным. Разработанный скрипт выполняет все возложенные на него функции, связанные с защитой сайта от сканирования, а также от хаотичных интенсивных запросов.

Листинг программы

/**
 * Класс проверки и блокировки ip-адреса.
 */
class BotBlockIp {
    /**
     * Время блокировки в секундах.
     */
    const blockSeconds = 60;
    /**
     * Интервал времени запросов страниц.
     */
    const intervalSeconds = 1;
    /**
     * Количество запросов страницы в интервал времени.
     */
    const intervalTimes = 4;
    /**
     * Флаг подключения всегда активных пользователей.
     */
    const isAlwaysActive = true;
    /**
     * Флаг подключения всегда заблокированных пользователей.
     */
    const isAlwaysBlock = true;
    /**
     * Путь к директории кэширования активных пользователей.
     */
    const pathActive = 'active';
    /**
     * Путь к директории кэширования заблокированных пользователей.
     */
    const pathBlock = 'block';
    /**
     * Флаг абсолютных путей к директориям.
     */
    const pathIsAbsolute = false;
    /**
     * Список всегда активных пользователей.
     */
    public static $alwaysActive = array(
 
    );

    /**
     * Список всегда заблокированных пользователей.
     */
    public static $alwaysBlock = array(
 
    );

    /**
     * Метод проверки ip-адреса на активность и блокировку.
     */
    public static function checkIp() {
		
	// Если это поисковый бот, то выходим ничего не делая
	if(self::is_bot()){
		return;
	}

        // Получение ip-адреса
        $ip_address = self::_getIp();

        // Пропускаем всегда активных пользователей
        if (in_array($ip_address, self::$alwaysActive) && self::isAlwaysActive) {
            return;
        }

        // Блокируем всегда заблокированных пользователей
        if (in_array($ip_address, self::$alwaysBlock) && self::isAlwaysBlock) {
	    header('HTTP/1.0 403 Forbidden');
            echo '';
            echo '';
            echo '';
            echo 'Вы заблокированы';
            echo '';
            echo '';
            echo '';
            echo '

'; echo 'Вы заблокированы администрацией ресурса.
'; exit; } // Установка путей к директориям $path_active = self::pathActive; $path_block = self::pathBlock; // Приведение путей к директориям к абсолютному виду if (!self::pathIsAbsolute) { $path_active = str_replace('\\' , '/', dirname(__FILE__) . '/' . $path_active . '/'); $path_block = str_replace('\\' , '/', dirname(__FILE__) . '/' . $path_block . '/'); } // Проверка возможности записи в директории if (!is_writable($path_active)) { die('Директория кэширования активных пользователей не создана или закрыта для записи.'); } if (!is_writable($path_block)) { die('Директория кэширования заблокированных пользователей не создана или закрыта для записи.'); } // Проверка активных ip-адресов $is_active = false; if ($dir = opendir($path_active)) { while (false !== ($filename = readdir($dir))) { // Выбирается ip + время активации этого ip if (preg_match('#^(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})_(\d+)$#', $filename, $matches)) { if ($matches[2] >= time() - self::intervalSeconds) { if ($matches[1] == $ip_address) { $times = intval(trim(file_get_contents($path_active . $filename))); if ($times >= self::intervalTimes - 1) { touch($path_block . $filename); unlink($path_active . $filename); } else { file_put_contents($path_active . $filename, $times + 1); } $is_active = true; } } else { unlink($path_active . $filename); } } } closedir($dir); } // Проверка заблокированных ip-адресов $is_block = false; if ($dir = opendir($path_block)) { while (false !== ($filename = readdir($dir))) { // Выбирается ip + время блокировки этого ip if (preg_match('#^(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})_(\d+)$#', $filename, $matches)) { if ($matches[2] >= time() - self::blockSeconds) { if ($matches[1] == $ip_address) { $is_block = true; $time_block = $matches[2] - (time() - self::blockSeconds) + 1; } } else { unlink($path_block . $filename); } } } closedir($dir); } // ip-адрес заблокирован if ($is_block) { header('HTTP/1.0 502 Bad Gateway'); echo ''; echo ''; echo ''; echo '502 Bad Gateway'; echo ''; echo ''; echo ''; echo '

502 Bad Gateway

'; echo '

'; echo 'К сожалению, Вы временно заблокированы, из-за частого запроса страниц сайта.
'; echo 'Вам придется подождать. Через ' . $time_block . ' секунд(ы) Вы будете автоматически разблокированы.'; echo '

'; echo ''; echo ''; exit; } // Создание идентификатора активного ip-адреса if (!$is_active) { touch($path_active . $ip_address . '_' . time()); } } /** * Метод получения текущего ip-адреса из переменных сервера. */ private static function _getIp() { // ip-адрес по умолчанию $ip_address = '127.0.0.1'; // Массив возможных ip-адресов $addrs = array(); // Сбор данных возможных ip-адресов if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { // Проверяется массив ip-клиента установленных прозрачными прокси-серверами foreach (array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $value) { $value = trim($value); // Собирается ip-клиента if (preg_match('#^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$#', $value)) { $addrs[] = $value; } } } // Собирается ip-клиента if (isset($_SERVER['HTTP_CLIENT_IP'])) { $addrs[] = $_SERVER['HTTP_CLIENT_IP']; } // Собирается ip-клиента if (isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) { $addrs[] = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP']; } // Собирается ip-клиента if (isset($_SERVER['HTTP_PROXY_USER'])) { $addrs[] = $_SERVER['HTTP_PROXY_USER']; } // Собирается ip-клиента if (isset($_SERVER['REMOTE_ADDR'])) { $addrs[] = $_SERVER['REMOTE_ADDR']; } // Фильтрация возможных ip-адресов, для выявление нужного foreach ($addrs as $value) { // Выбирается ip-клиента if (preg_match('#^(\d{1,3}).(\d{1,3}).(\d{1,3}).(\d{1,3})$#', $value, $matches)) { $value = $matches[1] . '.' . $matches[2] . '.' . $matches[3] . '.' . $matches[4]; if ('...' != $value) { $ip_address = $value; break; } } } // Возврат полученного ip-адреса return $ip_address; } /** * Метод проверки на поискового бота. */ private static function is_bot() { if (!empty($_SERVER['HTTP_USER_AGENT'])) { $options = array( 'YandexBot', 'YandexAccessibilityBot', 'YandexMobileBot','YandexDirectDyn', 'YandexScreenshotBot', 'YandexImages', 'YandexVideo', 'YandexVideoParser', 'YandexMedia', 'YandexBlogs', 'YandexFavicons', 'YandexWebmaster', 'YandexPagechecker', 'YandexImageResizer','YandexAdNet', 'YandexDirect', 'YaDirectFetcher', 'YandexCalendar', 'YandexSitelinks', 'YandexMetrika', 'YandexNews', 'YandexNewslinks', 'YandexCatalog', 'YandexAntivirus', 'YandexMarket', 'YandexVertis', 'YandexForDomain', 'YandexSpravBot', 'YandexSearchShop', 'YandexMedianaBot', 'YandexOntoDB', 'YandexOntoDBAPI', 'Googlebot', 'Googlebot-Image', 'Mediapartners-Google', 'AdsBot-Google', 'Mail.RU_Bot', 'bingbot', 'Accoona', 'ia_archiver', 'Ask Jeeves', 'OmniExplorer_Bot', 'W3C_Validator', 'WebAlta', 'YahooFeedSeeker', 'Yahoo!', 'Ezooms', '', 'Tourlentabot', 'MJ12bot', 'AhrefsBot', 'SearchBot', 'SiteStatus', 'Nigma.ru', 'Baiduspider', 'Statsbot', 'SISTRIX', 'AcoonBot', 'findlinks', 'proximic', 'OpenindexSpider','statdom.ru', 'Exabot', 'Spider', 'SeznamBot', 'oBot', 'C-T bot', 'Updownerbot', 'Snoopy', 'heritrix', 'Yeti', 'DomainVader', 'DCPbot', 'PaperLiBot' ); foreach($options as $row) { if (stripos($_SERVER['HTTP_USER_AGENT'], $row) !== false) { return true; } } } return false; } } // Проверка текущего ip-адреса BotBlockIp::checkIp();

Данный скрипт можно внедрить непосредственно в индексную страницу, либо отдельно в php файле, включив его вызов в самом начале файла.

Комментариев ещё нет, будьте первым!
Написать комментарий

Чтобы писать комментарии, вам нужно войти на сайт

+74957888803
customer@8cores.ru
Telegram