Сегодня поговорим о защите сервера от большого количества запросов.
Не секрет, что любая вычислительная система имеет ограничение на нагрузку. Зная это, несложно будет вывести её из строя, просто загрузив массой запросов. После этого она может стать неработоспособной, что и является положительным результатом для недоброжелателей, которые всё это затеяли.
DOS-атака — популярный тип атаки на систему. Заключается в том, что хакер посылает большое количество запросов серверу. Атака может производиться как с одного, так и с тысячи компьютеров. Почему бы и немного не защититься от подобных атак. Ниже представлена реализация контроля запросов к серверу. Для написания использовался javascript для платформы Node.js.
Создадим json-файл конфигураций:
где enable-включатель защиты, maxReq — это максимальное количество запросов в time миллисекунд.
Класс Limiter будет отвечать за контроль запросов.
где переменная requests хранит очередь запросов. Значение элемента очереди — время запроса. Размер очереди не будет превышать maxReq.
Функция getRequestsCount() возвращает количество запросов к серверу за последние time миллисекунд.
Во время любого запроса к нашему сайту, будет вызываться функция newRequest(). Реализация ниже:
Применение контроля запросов можно произвести в методе обращения к серверу.
Весь код можно посмотреть на bitbucket bitbucket.org/denzo1993/limiter
Описанное решение от атак не является идеальным, но, возможно, может найти свое применение в ваших проектах.
Всем спасибо!
Не секрет, что любая вычислительная система имеет ограничение на нагрузку. Зная это, несложно будет вывести её из строя, просто загрузив массой запросов. После этого она может стать неработоспособной, что и является положительным результатом для недоброжелателей, которые всё это затеяли.
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
Описанное решение от атак не является идеальным, но, возможно, может найти свое применение в ваших проектах.
Всем спасибо!
walkman7
Сомнительная защита от DDoS, так как атакующий просто забьет очередь запросов и пользовательский (хороший) в ответочку получит throw Error('Server is too busy');
crmMaster
Именно. Данный код не избавит от Ddos, а ускорит отказ в обслуживании. Кроме того, поскольку нагрузка не будет выше определенного уровня, системы мониторинга просто не среагируют на проблему.
Так что это не решение, а костыль, да еще мешающий понять истинную проблему.
denzo1993 Автор
Все-таки это решение подойдёт больше для контроля нагрузки сервера. Например, позволяющее производить только n операций в t времени.
denzo1993 Автор
Согласен, что в итоге система будет для «хорошего» клиента неработоспособна. В таком случае можно как-нибудь допилить класс и добавить фильтрацию ip-адресов.
walkman7
Вот и пришли мы к тому, что ваше решение никому не нужно кроме вас, так как с этой задачей справляется nginx.org/en/docs/http/ngx_http_limit_req_module.html