Защита сайта от сканирования и хаотичных интенсивных запросов

в 9:27, , рубрики: защита сайта, нагрузка, сайт
image

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

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

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

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

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

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

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

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

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

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

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

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

Логика работы разрабатываемой системы защиты сайта, создаваемой в виде php-скрипта, приведена на рисунке:

image

В процессе разработки скрипта важным моментом является выбор способа хранения получаемой информации. В нашем случае, это 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).
Разработанный скрипт содержит один класс TBlockIp. Данный класс включает такие методы:
— checkIp(). Данный метод реализовывает возможность произведения проверки IP-адреса пользователя на его блокировку или же на активность. При этом пропускаются IP-адреса, внесенные в список «всегда разрешенных IP-адресов», а IP-адреса внесенные в список «всегда запрещенных IP-адресов» наоборот блокируются. В случае, если пользовательский IP-адрес не найден в массиве возможных IP-адресов – скрипт создаст идентификатор нового активного IP-адреса;
— _getIp(). Данный метод дает возможность получить текущий IP-адрес пользователя, выбираемый из всех возможных IP-адресов (фильтрация производиться до выявления нужного IP-адреса клиента). Метод возвращает полученный IP-адрес.

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

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

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

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

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

    /**
     * Метод проверки ip-адреса на активность и блокировку.
     */
    public static function checkIp() {

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

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

        // Блокируем всегда заблокированных пользователей
        if (in_array($ip_address, self::$alwaysBlock) && self::isAlwaysBlock) {
            echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
            echo '<html xmlns="http://www.w3.org/1999/xhtml">';
            echo '<head>';
            echo '<title>Вы заблокированы</title>';
            echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
            echo '</head>';
            echo '<body>';
            echo '<p style="background:#ccc;border:solid 1px #aaa;margin:30px au-to;padding:20px;text-align:center;width:700px">';
            echo 'Вы заблокированы администрацией ресурса.<br />';
            echo '</p>';
            echo '</body>';
            echo '</html>';
            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 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
            echo '<html xmlns="http://www.w3.org/1999/xhtml">';
            echo '<head>';
            echo '<title>502 Bad Gateway</title>';
            echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />';
            echo '</head>';
            echo '<body>';
            echo '<h1 style="text-align:center">502 Bad Gateway</h1>';
            echo '<p style="background:#ccc;border:solid 1px #aaa;margin:30px au-to;padding:20px;text-align:center;width:700px">';
            echo 'К сожалению, Вы временно заблокированы, из-за частого запроса страниц сайта.<br />';
            echo 'Вам придется подождать. Через ' . $time_block . ' секунд(ы) Вы будете автоматически разблокированы.';
            echo '</p>';
            echo '</body>';
            echo '</html>';
            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;
    }

}

// Проверка текущего ip-адреса
TBlockIp::checkIp();

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

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

include '/block/index.php';

В это случае нужно создать в корне папку «block», в ней еще папки «active» и «block» и файл «index.php» (сюда копируем выше приведенный код).

3 Тестирование php-скрипта, внедренного в сайт

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

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

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

Созданный php-скрипт должен делать именно то, для чего, собственно говоря, он и был создан. Применительно к разработанному и созданному в данной работе php-скрипту можно сказать так: если пользователь сможет отправить за определенный промежуток времени (по умолчанию 15 секунд) больше заданного количества запросов (по умолчанию – 3 запроса) к страницам сайта и скрипт не заблокирует его IP-адрес, значит, в работу написанного Web-приложения закралась ошибка. В целом, тестирование представляет собой деятельность, которая направлена на выявление подобного рода несоответствий, существующих между ожидаемым поведением написанного php-скрипта и действительным его поведением. За счет выявления несоответствия в поведении скрипта, а также его некорректного поведения еще во время разработки, у разработчика есть возможность существенно снизить вероятность того, что с такого рода поведением скрипта столкнется и пользователь. Проводить тестирование программы (в нашем случае, написанного php-скрипта) можно как вручную, так и при помощи специализированных онлайнсервисов.

3.1 Тестирование вручную

При тестировании написанного php-скрипта вручную, нам необходимо проверить выполняет ли скрипт возложенные на него задачи. В частности, ограничивает ли количество запросов к страницам сайта, исходящим от одного и того же пользователя, в случае, если их частота превышает допустимый предел в определенный промежуток времени. Для проверки работоспособности скрипта нам, прежде всего, необходимо внедрить его в код сайта. Для этого можно воспользоваться такой языковой конструкцией:
include «block/index.php»;

При таком включении скрипт должен быть расположен в папке block. Следует учесть, что в случае, если система управления содержимым сайта использует для страниц создание, так называемых Friendly URL, т.е. веб-адресов, которые удобны для восприятия человеком (в данном случае имеется ввиду создание каких-либо многоуровневых структур, например, /news/sport/2003/10/), или же загружает страницы с адресом отличным от корня папки (например, /news/sport.php), возникнет необходимость правильного указания адреса к скрипту. В подобной ситуации вполне может быть указан абсолютный путь к скрипту.

Само по себе тестирование написанного php-скрипта будет заключаться в отправке запросов к страницам сайта. В процессе тестирования нам нужно проверить: пропускает ли созданный скрипт заданное максимальное количество запросов (по умолчанию – 3 запроса) в определенный промежуток времени (по умолчанию – 15 секунд). Прежде всего, нам необходимо проверить как скрипт справляется со своей основной функцией, т.е. непосредственной блокировкой интенсивных запросов на страницы сайта, исходящих от одного и того же пользователя. Проверка количества запросов, которые могут быть отправлены к страницам сайта, показала, что на протяжении отведенных пятнадцати секунд отправить к страницам сайта более трех запросов нет возможности. В частности, если пользователь отправляет больше трех запросов, то получает сообщение о временной блокировке, приведенное на рисунке:

image

Таким образом, тестирование показало, что скрипт работает именно так, как предполагалось: блокирует пользователя на определенное время (по умолчанию – на одну минуту) в случае, если в определенный интервал времени количество запросов от одного пользователя превышает заданный показатель (по умолчанию – 3 запроса). Следующим этапом тестирования будет проверка, работоспособности отдельных функций написанного php-скрипта. В частности, нужно проверить, как будет работать скрипт если IP-адрес тестирующего пользователя будет добавлен в список «всегда разрешенных IP-адресов». Также нужно проверить, как будет вести себя скрипт, если IP-адрес тестирующего пользователя будет добавлен в список «всегда запрещенных IP-адресов».

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

image

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

3.2 Тестирование при помощи онлайн-сервисов

Тестирование написанного php-скрипта, при помощи онлайнсервисов, даст возможность узнать, точное количество трафика необходимого для загрузки страниц сайта, а также поможет точно установить «пропускную способность» написанного php-скрипта для запросов, которые будут отправляться различными автоматическими сервисами или же программами. Последний параметр очень важен, ведь одной из задач скрипта является защита сайта от сканирования при помощи программ-краулеров. Такого рода тестирование не только поможет сделать вывод об необходимом количестве трафика и процессорного времени, но и о том, доступна ли будет информация представленная на сайте для программных средств, запрашивающих страницы в автоматическом режиме. Для начала оценим среднее время загрузки страниц сайта, при разных скоростях соединения. Также оценим и размер загружаемых пользователем страниц. Для проведения такого рода тестирования воспользуемся онлайн-сервисом, расположенным по адресу analyze.websiteoptimization.com. Размеры загружаемых страниц, определенные сервисом, приведены на рисунке:

image

С учетом того, что тестируемый нами сайт состоит лишь из одной страницы, размер которой составляет 1511 байт, она загрузиться за 0,51 секунды (при скорости соединения 56 К) или за 0,21 секунды (при скорости соединения пользователя 1,44 Mbps). Скорость загрузки страниц при разной скорости соединения пользователя приведена на рисунке:

image

Как видно из приведенной на рисунке информации, даже при самой низкой скорости соединения (14,4 К) страница сайта грузится довольно быстро – за 1,4 секунды. В то же время, если скорость соединения пользователя довольно высока (в частности, 1,44 Mbps), то страница будет загружена буквально моментально (за 0,21 секунды). Отметим, что низкая скорость загрузки на данном ресурсе корректируется на коэффициент потери пакетов (этот коэффициент равен 0,7). Также учитывается и время задержки равное в среднем 0,2 секунды на загрузку одной страницы. Именно эти параметры и объясняют, почему существенный рост скорости соединения не приводит к столь же существенному сокращению времени загрузки страницы. Отметим, что данный сервис кроме оценки основных параметров загрузки страниц сайта также предоставляет общие результаты анализа сайта и, конечно же, рекомендации направленные на улучшение всех параметров загрузки страниц сайта. Результаты анализа и рекомендации сервиса приведены на рисунке:

image

Как видно из рисунка, все показатели тестируемого сайта по всем анализируемым параметрам находятся в пределах нормы. В частности, сервис констатирует, что количество страниц сайта, объектов на них, а также размеры этих страниц и объектов находятся в допустимых пределах. Исходя из полученных данных оптимизация тестируемому сайту не требуется, ведь сайт соответствует нормам по всем анализируемым параметрам. Иначе говоря, объемы загружаемой с сайта информации (или страниц сайта) довольно малы и позволяют экономить ресурсы как веб-сервера, так и пользователя. Т.е. разработанный скрипт не нагружает сайт и, фактически, его присутствие не заметно. Что подчеркивает проведенное тестирование. Проверку скорости загрузки страниц сайта, а также их доступности для других скриптов можно выполнить при помощи такого онлайн-сервиса как www.pr-cy.ru. Результат теста, сделанного при помощи данного онлайн-сервиса, приведен на рисунке:

image

Как видно, из полученных данных при средней скорости загрузки 30,31 Кб/сек, время загрузки страницы составляет 0,05 секунды. В то же время при средней скорости 37,89 Кб/сек, время загрузки страницы составляет уже 0,04 секунды. В то же время, тестирование показало, что разработанный в данной работе скрипт блокирует больше трех запросов к страницам сайта, исходящих от одного IP-адреса и тем самым снижает излишнюю нагрузку и весьма усложняет попытки или вовсе делает невозможным подбор пароля к сайту.

3.3 Результаты тестирования php-скрипта, внедренного в сайт

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

Тестирование сайта, в который внедрен разработанный php-скрипт, показало, что все показатели тестируемого сайта по всем анализируемым параметрам находятся в пределах нормы. В частности, сервис констатирует, что количество страниц сайта, объектов на них, а также размеры этих страниц и объектов находятся в допустимых пределах. Исходя из полученных данных оптимизация тестируемому сайту не требуется, ведь сайт соответствует нормам по всем анализируемым параметрам. Иначе говоря, объемы загружаемой с сайта информации (или страниц сайта) довольно малы и позволяют экономить ресурсы как веб-сервера, так и пользователя. Ранее скрипт использовался на сайте www.free-soft.name и на www.dota-manual.ru, но позднее были предприняты более серьезные меры защиты. Однако, на первых порах, данный скрипт существенно снижал нагрузку на недорогой хостинг и позволял крутить сайты с посещаемостью 5000+ хостов в сутки.

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

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

Автор: LeoRed

Источник

Поделиться

* - обязательные к заполнению поля