Простой контроль нагрузки на сервер (Node.js)

от автора

Сегодня поговорим о защите сервера от большого количества запросов.

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

DOS-атака — популярный тип атаки на систему. Заключается в том, что хакер посылает большое количество запросов серверу. Атака может производиться как с одного, так и с тысячи компьютеров. Почему бы и немного не защититься от подобных атак. Ниже представлена реализация контроля запросов к серверу. Для написания использовался javascript для платформы Node.js.

Создадим json-файл конфигураций:

{   "enable": true,   "maxReq":  20,   "time": 10000 } 

где enable-включатель защиты, maxReq — это максимальное количество запросов в time миллисекунд.

Класс Limiter будет отвечать за контроль запросов.

function Limiter() {     this.requests = []; // Очередь запросов [значение = время запроса] } 

где переменная requests хранит очередь запросов. Значение элемента очереди — время запроса. Размер очереди не будет превышать maxReq.

Функция getRequestsCount() возвращает количество запросов к серверу за последние time миллисекунд.

Limiter.prototype.getRequestsCount = function() {     var currentTime = new Date().getTime(); // текущее время     var counter = 0; // счетчик запросов     for(var i = 0; i<this.requests.length; ++i) {         // Инкрементируем счетчик, если время запроса попадает в нужный интервал         if(currentTime - this.requests[i] < params['time']) ++counter;     }     return counter; } 

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

Limiter.prototype.newRequest = function() {     // Выходим, если контроль трафика выключен     if(!params['enable']) return undefined;      // Если текущий запрос уже лишний, то кидаем исключение     if(this.getRequestsCount() >= params['maxReq']) throw Error('Server is too busy');      // Если очередь >= params['maxReq'], то удаляем старый запрос     if(this.requests.length >= params['maxReq']) this.requests.shift();      // И добавляем  в очередь новый запрос     this.requests.push(new Date().getTime());      // Вернем текущее количество запросов     return this.getRequestsCount(); } 

Применение контроля запросов можно произвести в методе обращения к серверу.

server.on('request', function(req, res) {     // Запросы favicon откинем в сторону     if(req.url === '/favicon.ico') return;      var message = ''; // ответ клиенту     try {         // Добавим новый запрос в очередь         var count = limiter.newRequest();          // Если newRequest() не вернет исключение, то         // выполняем необходимые вычисления и генерируем         // страницу для пользователя         message = 'HARD SCRIPT! WOW WOW!!!\n';         message += 'Requests for last '             + limiter.getTime() + ' ms: '             + count;     } catch(e) {         // Если newRequest() кидает исключение, то         // говорим пользователю, что сервер слишком         // нагружен и не может выполнить вычисления         message = e.message;     }     // Отправляем ответ пользователю     res.end(message); }); 

Весь код можно посмотреть на bitbucket bitbucket.org/denzo1993/limiter

Описанное решение от атак не является идеальным, но, возможно, может найти свое применение в ваших проектах.

Всем спасибо!

ссылка на оригинал статьи http://habrahabr.ru/post/263049/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *