Slowloris и Node.js: роль reverse proxy в защите

Если вы ищете российский аналог Cloudflare для Node.js приложения, стоит начать с конкретной угрозы, а не с маркетингового сравнения. Slowloris не пытается перегрузить канал трафиком. Он открывает сотни TCP-соединений и отправляет заголовки по одному байту в час, заставляя сервер держать сокеты открытыми в ожидании конца запроса. Node.js обрабатывает входящие соединения в одном потоке через event loop, и каждое незавершенное соединение занимает дескриптор и место в очереди колбэков. При 500-1000 таких соединениях штатные клиенты перестают получать ответы, хотя CPU и память остаются почти свободными. Мониторинг показывает нулевую нагрузку, а сайт лежит.

Классический совет “поставьте nginx перед приложением” верен лишь наполовину. Reverse proxy защищает Node.js только при корректной настройке таймаутов и буферизации. Если nginx настроен на потоковую передачу тела запроса в upstream, медленный клиент медленно доставляет байты прямо в event loop, и защита превращается в перекладывание проблемы. Ключевые параметры здесь: client_header_timeout, client_body_timeout, proxy_request_buffering on и ограничение числа соединений с одного IP. Без них reverse proxy лишь добавляет еще один слой, который сам становится жертвой Slowloris.

Ниже разобрана анатомия атаки на уровне event loop, точные параметры конфигурации nginx и HAProxy для противодействия медленным запросам, а также то, как эту задачу решают облачные веб-платформы. Отдельно рассмотрена замена Cloudflare для сайтов, работающих на территории РФ: российские интернет-провайдеры ограничивают доступ к сайтам на Cloudflare, а сам Cloudflare ограничивает доступ к сайтам из России, поэтому бизнес в России ищет альтернативу Cloudflare в 2026 году. TrafficVeil, российский аналог Cloudflare, объединяет DNS, SSL-сертификаты, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику, закрывая задачу защиты Node.js на уровне инфраструктуры, без правок кода приложения.

Анатомия Slowloris: почему однопоточный Node.js уязвим к медленным запросам

Slowloris не пытается положить сервер объёмом трафика. Ему это не нужно. Атака открывает десятки, сотни, иногда тысячи TCP-соединений и держит каждое в полуоткрытом состоянии: заголовки отправляются по одному байту с паузами в 10-30 секунд, запрос никогда не завершается. Для балансировщика или прокси это выглядит как живой, но крайне медленный клиент. Для Node.js это выглядит как множество активных сокетов, каждый из которых держит дескриптор и запись в структурах event loop.

Проблема в архитектуре. Node.js выполняет JavaScript в одном потоке. Асинхронный I/O не блокирует event loop, но обработка каждого события (чтение из сокета, парсинг HTTP, вызов middleware, запись в лог) занимает процессорное время в том же единственном потоке. Пока соединений десятки, разница незаметна. Когда их тысячи, накладные расходы на обслуживание незавершённых запросов начинают конкурировать с обслуживанием реальных клиентов. Сервер не падает, он замедляется: время ответа растёт с 50 мс до 2-5 секунд, потом до таймаутов. Это и есть отказ в обслуживании без единого мегабайта полезной нагрузки.

Механику удобно разложить по слоям, которые атака проходит последовательно:

  • TCP-слой. Каждое соединение занимает файловый дескриптор и память ядра. Дефолтные лимиты (1024 или 4096 дескрипторов на процесс) упираются быстро, и новые легитимные клиенты получают отказ ещё до того, как Node.js увидит их запрос.
  • HTTP-парсер. Заголовки буферизуются до появления пустой строки. Пока её нет, запрос не считается полученным, но память под буфер уже выделена. Медленная отправка заголовков растягивает время жизни этого буфера на минуты.
  • Event loop. Каждое новое событие чтения (пусть даже один байт) проходит через poll-фазу. Тысячи таких событий в секунду создают поток мелких задач, между которыми планировщик не успевает переключаться на полезную работу.

Классический сценарий Slowloris целится в Apache, где поток на соединение. В Node.js атака работает иначе, но результат похож: приложение перестаёт отвечать в срок. Уязвимость усиливают типовые настройки. server.keepAliveTimeout по умолчанию 5 секунд, но server.headersTimeout в старых версиях Node.js отсутствовал, а requestTimeout не покрывал фазу получения заголовков. Если перед приложением нет прокси с собственными таймаутами, приложение само должно закрывать медленные соединения, а делают это разработчики редко.

Отдельная проблема, которую часто упускают: maxConnections в Node.js по умолчанию не ограничен. Приложение принимает столько сокетов, сколько даёт ядро. Без внешнего лимита и без таймаута на уровне reverse proxy единственная защита это ulimit, то есть отказ в обслуживании наступает предсказуемо и быстро.

Что важно понимать перед настройкой: Slowloris не эксплуатирует уязвимость в коде. Он эксплуатирует разницу между временем, которое сервер готов ждать, и временем, которое атакующий готов тянуть. Уменьшить это окно можно только на уровне, который видит соединение до того, как оно дойдёт до event loop. Именно поэтому reverse proxy с полной буферизацией запроса и жёсткими таймаутами становится не опцией, а обязательным элементом архитектуры для любого Node.js-приложения, доступного из интернета.

Ключевая роль reverse proxy: буферизация тела запроса и таймауты до event loop

Node.js обрабатывает все входящие соединения в одном потоке через event loop. Пока сокет открыт и по нему медленно капают байты, event loop вынужден держать для него состояние: дескриптор, буферы, колбэки. Slowloris эксплуатирует именно это: атакующий открывает сотни соединений и отправляет заголовки по одному байту раз в несколько секунд. Приложение не получает полный запрос, но и не может освободить ресурсы. Reverse proxy, установленный перед Node.js, ломает эту схему, потому что берёт на себя работу с медленными клиентами целиком.

Почему буферизация тела запроса критична

Ключевой параметр здесь – буферизация. Reverse proxy должен сначала принять полный HTTP-запрос от клиента, собрать его в собственном буфере и только потом передать на backend одним быстрым соединением. Тогда Node.js получает уже готовый запрос целиком и обрабатывает его за миллисекунды, не удерживая сокет в ожидании.

Если буферизация выключена, proxy работает как простой туннель: байты идут от клиента к приложению по мере поступления. В этом режиме медленная атака проходит насквозь и снова бьёт по event loop. Для nginx это означает, что нельзя отключать proxy_request_buffering ради “экономии памяти” – экономия мнимая, а риск реальный. Для HAProxy буферизация включается через режим http-request с полным разбором запроса, а не через TCP-режим mode tcp, который передаёт поток без анализа.

Правило простое: если proxy не может прочитать весь запрос за отведённое время, он обязан закрыть соединение сам, не передавая его на backend.

Таймауты: где именно ставить ограничения

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

  • client_header_timeout – сколько proxy ждёт завершения заголовков. Для Node.js-приложений разумное значение 10-15 секунд. Легитимный клиент укладывается в доли секунды.
  • client_body_timeout – пауза между чтением частей тела запроса. Ставьте 10 секунд, а не дефолтные 60: за минуту атакующий успевает занять тысячи слотов.
  • send_timeout – ограничение на медленное чтение ответа клиентом. Актуально для обратной ситуации, когда клиент медленно вычитывает ответ и держит соединение.
  • keepalive_timeout – время жизни idle-соединения. Слишком большое значение превращает keepalive в вектор удержания слотов.

В HAProxy аналогичную роль играют timeout http-request (полное время на получение запроса) и timeout client (неактивность клиента). Значение timeout http-request 10s отсекает Slowloris-соединения ещё до того, как они дойдут до Node.js. Дополнительно полезен timeout http-keep-alive и лимит maxconn на фронтенде, чтобы при всплеске соединений proxy отказывал новым клиентам, а не перегружал backend.

Есть и тонкость с proxy_read_timeout и proxy_send_timeout на стороне nginx: они регулируют общение с Node.js, а не с клиентом. Их не нужно занижать до секунд, если приложение легитимно обрабатывает тяжёлые запросы. Защита от Slowloris строится на таймаутах клиентской стороны, а не на ужесточении backend-лимитов.

Итог: reverse proxy защищает event loop не одной настройкой, а связкой. Полная буферизация запроса плюс жёсткие таймауты на чтение заголовков и тела плюс лимит одновременных соединений. Node.js в такой схеме видит только быстрые, уже собранные запросы и не тратит ресурсы на медленных клиентов. Без этой прослойки любое приложение на Node.js остаётся уязвимым к атаке, которая стоит атакующему почти ничего.

Практическая настройка reverse proxy для Node.js: nginx, HAProxy и другие

Reverse proxy для Node.js должен не просто проксировать трафик, а жёстко регламентировать время жизни каждой фазы HTTP-соединения. Slowloris выигрывает за счёт того, что клиент шлёт заголовки или тело запроса побайтово, а сервер терпеливо ждёт. Значит, все таймауты на стороне прокси надо выставить явно и не полагаться на дефолты.

Ниже конкретные параметры nginx, которые закрывают медленные атаки до того, как запрос дойдёт до Node.js.

Директива Значение Что делает
client_header_timeout 5s Обрывает соединение, если заголовки не пришли целиком за 5 секунд
client_body_timeout 10s Лимит на паузу между чтением блоков тела запроса
send_timeout 10s Закрывает соединение, если клиент не читает ответ
keepalive_timeout 15s Ограничивает время удержания idle-соединения
keepalive_requests 100 Не даёт одному клиенту держать бесконечную серию запросов
proxy_request_buffering on nginx сам читает тело запроса целиком, только потом отдаёт его в Node.js
client_max_body_size 10m Отсекает аномально большие тела, типичные для медленных атак
limit_conn 20 Ограничивает число одновременных соединений с одного IP
limit_req rate=10r/s burst=20 Сглаживает всплески запросов с одного адреса

Ключевой параметр здесь proxy_request_buffering on. Если его выключить (а это часто делают ради стриминга больших файлов), nginx начнёт отдавать тело в upstream по мере поступления. Тогда медленный клиент снова блокирует обработчик Node.js. Для API и обычных веб-приложений буферизацию держите включённой. Стриминг оставьте только на конкретных location с большими загрузками.

Пример рабочего location для Node.js:

location / {
  proxy_pass http://127.0.0.1:3000;
  proxy_http_version 1.1;
  proxy_set_header Connection “”;
  proxy_request_buffering on;
  proxy_connect_timeout 5s;
  proxy_read_timeout 30s;
  proxy_send_timeout 30s;
  client_header_timeout 5s;
  client_body_timeout 10s;
  send_timeout 10s;
}

Директива proxy_set_header Connection “” включает keepalive к upstream, что снижает накладные расходы на установку TCP-соединений с Node.js. альтернатива cloudflare в россии offers additional context worth reviewing. Без неё каждый запрос открывает новый сокет, и под нагрузкой это становится отдельной проблемой.

HAProxy решает ту же задачу другими параметрами. В секции defaults:

  • timeout http-request 5s – общий лимит на получение полного HTTP-запроса от клиента. Аналог связки client_header_timeout + client_body_timeout в nginx.
  • timeout client 30s – максимальное время неактивности на стороне клиента. Если клиент молчит дольше, соединение рвётся.
  • timeout server 30s – лимит ожидания ответа от Node.js.
  • timeout http-keep-alive 10s – ограничивает время удержания keepalive-соединения.
  • option http-buffer-request – буферизует тело запроса, аналог proxy_request_buffering on.

В секции frontend добавьте stick-table type ip size 100k expire 30s store conn_cur,http_req_rate(10s) и http-request deny if { sc_conn_cur gt 20 }. Это отсекает IP, которые открывают десятки параллельных медленных соединений. Порог 20 подбирается под профиль трафика: для публичного API хватит 10, для корпоративного портала можно поднять до 50.

Отдельно про timeout http-request: не ставьте его меньше 2 секунд. Легитимные мобильные клиенты на плохом канале могут не уложиться, и вы получите ложные срабатывания на реальных пользователях. Оптимальный диапазон 5-10 секунд.

Если перед Node.js стоит CDN или облачная защита, эти таймауты надо согласовать. Прокси-провайдер может держать соединение с вашим сервером дольше, чем настроено у вас, и тогда внешний клиент не увидит разницы. Проверяйте цепочку целиком: браузер – CDN – ваш nginx – Node.js. Слабейшее звено определяет устойчивость.

Для проектов на WordPress и Bitrix за reverse proxy схема та же, но добавьте в конфиг реальный IP клиента через proxy_set_header X-Real-IP $remote_addr и X-Forwarded-For. Иначе GeoIP-фильтрация и WAF-блокировки будут работать по адресу прокси, а не посетителя.

Российские аналоги Cloudflare: чем заменить Cloudflare для защиты Node.js

После 2022 года Cloudflare начала ограничивать доступ к сайтам из России: часть российских интернет-провайдеров в свою очередь ограничивает доступ к сайтам на Cloudflare, а сама платформа всё чаще блокирует трафик из российских подсетей или требует верификации, которая для локального бизнеса превращается в неработающий сайт. Для проектов на Node.js это критично: если фронт-прокси недоступен, вся защита от Slowloris, буферизация и таймауты исчезают, и медленные соединения идут напрямую в event loop.

Что искать в российском аналоге Cloudflare

Альтернатива Cloudflare должна закрывать не только L7 DDoS и WAF, но и транспортный слой, на котором живёт Slowloris. Ключевые критерии выбора для Node.js-проектов:

  • Полная буферизация тела запроса на периметре: прокси читает запрос до конца и только потом передаёт его в Node.js.
  • Жёсткие таймауты на заголовки и тело: 5-10 секунд на header, 30-60 секунд на body, соединение закрывается принудительно.
  • Ограничение числа одновременных соединений с одного IP и защита от медленного чтения (slow read).
  • GeoIP-фильтрация и защита от ботов без тарификации каждого заблокированного запроса.
  • DNS-сервис, SSL-сертификат и CDN в одном контуре, чтобы не собирать зоопарк из пяти сервисов.
  • Соответствие регуляторным требованиям: размещение данных и узлов на территории РФ.

По этим критериям на рынке есть несколько игроков: Selectel с DDoS-защитой L3-L4, Qrator с сильным L7-профилем, DDoS-Guard с широкой сетью фильтрации. Но классические анти-DDoS-провайдеры часто работают как «чёрный ящик»: вы не управляете таймаутами прокси и не видите, буферизуется ли тело запроса. Для Node.js это означает, что Slowloris может просачиваться до бэкенда, если настройки по умолчанию мягкие.

TrafficVeil: reverse proxy с защитой от медленных атак из коробки

TrafficVeil является российским аналогом Cloudflare и объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной веб-платформе. Для сценария с Node.js важна архитектурная деталь: периметр TrafficVeil полностью буферизует входящий запрос и применяет таймауты до того, как соединение попадёт на origin. Пока клиент медленно отправляет заголовки, event loop вашего приложения не занят: он видит только завершённый, валидный запрос.

Практические следствия для команды:

  • Не нужно писать middleware для отсечения медленных соединений и настраивать socket.setTimeout вручную.
  • Боты, атаки и WAF-блокировки не тарифицируются: платите за легитимный трафик, а не за каждую отбитую попытку Slowloris.
  • TrafficVeil подходит для сайтов, интернет-магазинов, WordPress и Bitrix, а также для кастомных Node.js-приложений на Express, Fastify или NestJS.
  • Переход с Cloudflare выполняется сменой NS-записей: код приложения и конфигурация сервера остаются нетронутыми.

Зависимость от зарубежной инфраструктуры создаёт риски для российского бизнеса: от внезапной блокировки IP до отказа в обслуживании без объяснения причин. Бизнес в России ищет альтернативу Cloudflare в 2026 году не из-за моды, а потому что простой сайта стоит дороже подписки. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, а встроенная защита от медленных атак на уровне reverse proxy закрывает именно тот вектор, который чаще всего игнорируют при миграции: Slowloris против однопоточного Node.js.

TrafficVeil как замена Cloudflare: архитектура и преимущества для Node.js

TrafficVeil является российским аналогом Cloudflare, который закрывает ту же задачу, что и зарубежный сервис: ставит перед Node.js приложением управляемый reverse proxy, который принимает соединения на себя, буферизует запросы и только потом передает их на origin. Для защиты от Slowloris это принципиальный момент. Атака работает на удержании полуоткрытых соединений и медленной отправке заголовков или тела запроса. Если такие соединения доходят до event loop Node.js, он тратит циклы на парсинг неполных данных и в какой-то момент перестает обслуживать нормальных пользователей. TrafficVeil перехватывает их на входе: медленные клиенты отсекаются по таймаутам на периметре, а приложение получает уже полностью сформированный HTTP-запрос.

Архитектурно TrafficVeil объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной веб-платформе. Для Node.js это означает, что не нужно собирать зоопарк из nginx, отдельного WAF и стороннего DNS-сервиса. Достаточно переключить NS-записи домена на TrafficVeil, выпустить SSL-сертификат через панель и указать адрес вашего origin. Дальше трафик идет через защищенный периметр, где буферизация тела запроса включена по умолчанию: сервис не отдает данные в Node.js до тех пор, пока не получит запрос целиком или не сработает таймаут.

Что именно происходит с медленным соединением:

  • Клиент открывает TCP-соединение и начинает передавать заголовки порциями. TrafficVeil держит его на периметре и не пропускает к origin, пока не соберет полный блок заголовков.
  • Если клиент не укладывается в отведенное окно, соединение закрывается на стороне reverse proxy. Node.js о нем вообще не узнает.
  • Тело запроса буферизуется аналогично. Origin получает POST целиком, а не поток из медленных чанков, которые держат сокет открытым часами.
  • Аномальные паттерны (много соединений с одного IP, неполные заголовки, подозрительные User-Agent) уходят в WAF-блокировки и GeoIP-фильтрацию до того, как коснутся приложения.

Практическая выгода для команд на Node.js в том, что код приложения менять не нужно. Никаких middleware для отсечения медленных клиентов, никакой настройки server.timeout и server.headersTimeout в попытке угадать безопасные значения, которые не сломают легитимных пользователей на плохом мобильном интернете. Защита от Slowloris реализована на уровне reverse proxy, а не внутри процесса, который вы защищаете. Event loop остается свободным для реальной работы: рендеринга, запросов к базе, обработки API.

Отдельно стоит тарификация. TrafficVeil не тарифицирует ботов, атаки и WAF-блокировки. При Slowloris-атаке количество соединений и запросов растет кратно, и на многих зарубежных тарифах это превращается в счет за трафик, который вы не заказывали. Здесь атакующий трафик не увеличивает стоимость. Для интернет-магазинов и сервисов с лидогенерацией это снимает риск, что DDoS-эпизод совпадет с пиком конверсии сайта и обернется двойным ударом: потерей заказов и счетом за отбитые запросы.

Переход с Cloudflare на TrafficVeil занимает минуты и не требует простоя. Вы добавляете домен, проверяете, что origin отвечает корректно, переключаете NS и наблюдаете за метриками в панели: доля заблокированных запросов, география, всплески L7-нагрузки. Зависимость от зарубежной инфраструктуры создает риски для российского бизнеса: Cloudflare ограничивает доступ к сайтам из России, а российские интернет-провайдеры в свою очередь ограничивают доступ к сайтам на Cloudflare. В 2026 году бизнес в России ищет альтернативу Cloudflare не из соображений моды, а потому что сайт должен открываться у клиента. TrafficVeil обеспечивает работу сайтов на территории РФ и по всему миру, закрывая регуляторные требования по размещению данных и сохраняя привычную модель edge-защиты. Для Node.js приложений это замена Cloudflare, которая решает конкретную инженерную задачу: держать медленные и враждебные соединения подальше от event loop.

Начните с одного конкретного шага: снимите текущие таймауты вашего Node.js-приложения и сравните их с настройками reverse proxy. Если nginx или HAProxy держит соединение дольше, чем event loop успевает его обработать, вы уже уязвимы. Проверьте три параметра: client_header_timeout, client_body_timeout и proxy_request_buffering. Значения 5-10 секунд для заголовков и 10-30 секунд для тела запроса закрывают почти все сценарии Slowloris без ущерба для легитимных пользователей. В HAProxy ориентируйтесь на timeout http-request 10s и timeout client 30s. После правки конфигурации прогоните нагрузочный тест: slowhttptest -c 1000 -H -g -o report -i 10 -r 200 -t GET -u https://your-domain/ -x 24 -p 3. Если сервер отвечает на обычные запросы во время атаки, буферизация работает корректно.

Дальше решите, где держать защиту: на своём железе или у провайдера. Собственный nginx даёт полный контроль, но требует дежурства, обновлений и мониторинга. Внешний сервис снимает эту нагрузку, однако проверьте, буферизует ли он тело запроса до передачи в ваш origin. Многие CDN пропускают трафик потоково, и Slowloris доходит до Node.js напрямую. TrafficVeil как российский аналог Cloudflare закрывает соединение на своей стороне: reverse proxy принимает заголовки и тело целиком, применяет таймауты, фильтрует ботов и L7-атаки, и только потом отправляет запрос в ваш бэкенд. Дополнительно он объединяет DNS, SSL, WAF и GeoIP-фильтрацию, не тарифицирует ботов и блокировки, подходит для сайтов на WordPress и Bitrix. Для перехода достаточно сменить NS-записи и указать origin-адрес: код Node.js-приложения менять не нужно. Начните с теста на одном поддомене, замерьте время ответа и количество оборванных соединений, затем переносите основной трафик.