Ограничение частоты запросов в ASP.NET Core

Быстрые ссылки
Почему стоит ограничивать запросы
Настройка rate limiting в ASP.NET Core
Конфигурация и примеры
Почему стоит ограничивать запросы
Ограничение частоты запросов полезно по нескольким причинам:
- Защита от простых DDoS-атак и автоматизированных ботов.
- Предотвращение перегрузки дорогих по ресурсам конечных точек.
- Контроль использования публичных API и предотвращение злоупотреблений одним клиентом.
Важно: провайдер облака может обеспечивать защиту на сетевом уровне (Layer 3/4). Тем не менее, защита на уровне приложения закрывает сценарии, когда сетевой фильтр пропускает трафик или когда атака нацелена на ресурсоёмкие операции внутри приложения.
Краткая модель мышления (mental model)
Представьте систему как ресторан:
- Входная дверь — сеть (облако/балансировщик).
- Хост/сервер — кухня, где ограничение контролирует количество одновременно принятых заказов.
- Правила rate limiting — менеджер, который не допускает одного гостя делать бесконечно много заказов.
Эта модель помогает понять, почему нужен и сетевой, и прикладной контроль.
Настройка rate limiting в ASP.NET Core
Blazor использует ASP.NET Core как основу сервера, поэтому конфигурация делается на уровне ASP.NET Core. В .NET нет встроенной функциональности rate limiting (по состоянию на описываемый пакет); популярное решение — пакет NuGet:
AspNetCoreRateLimitУстановите пакет через менеджер NuGet (Visual Studio -> Manage NuGet Packages…).

Найдите и установите пакет:

Добавление сервисов в Startup.cs
Все сервисы регистрируются в Startup.cs в методе ConfigureServices. Минимальный набор регистраций из примера пакета выглядит так:
// needed to load configuration from appsettings.json
services.AddOptions();
// needed to store rate limit counters and ip rules
services.AddMemoryCache();
//load general configuration from appsettings.json
services.Configure(Configuration.GetSection("IpRateLimiting"));
// inject counter and rules stores
services.AddInMemoryRateLimiting();
// configuration (resolvers, counter key builders)
services.AddSingleton(); В конвейере обработки запросов (метод Configure) подключается middleware:
app.UseIpRateLimiting();Примечание: in-memory хранение счётчиков работает только в рамках одного экземпляра приложения. При балансировке нагрузки необходимо использовать распределённое хранилище (Redis или другое), чтобы счётчики были общими для всех инстансов.
Конфигурация в appsettings.json
После регистрации сервисов настройте правила в appsettings.json. Пример конфигурации (сохранён для точности синтаксиса):
"IpRateLimiting": {
"EnableEndpointRateLimiting": false,
"StackBlockedRequests": true,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
"EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
"ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 2
},
{
"Endpoint": "*",
"Period": "15m",
"Limit": 100
},
{
"Endpoint": "*",
"Period": "12h",
"Limit": 1000
},
{
"Endpoint": "*",
"Period": "7d",
"Limit": 10000
}
]
}Перечисленные параметры:
- EnableEndpointRateLimiting: включить правила на уровне конкретных эндпоинтов.
- StackBlockedRequests: если true, блокированные запросы также увеличивают счётчик.
- RealIpHeader / ClientIdHeader: заголовки реального клиента при использовании обратного прокси.
- HttpStatusCode: код ответа при превышении лимита (обычно 429).
- IpWhitelist / EndpointWhitelist / ClientWhitelist: исключения.
- GeneralRules: набор базовых правил с периодами и лимитами.
Советы по составлению правил
- Для публичных API задавайте более строгие лимиты для анонимных клиентов и более мягкие для авторизованных (по ключам/токенам).
- Выделяйте отдельные правила для ресурсоёмких эндпоинтов.
- Тестируйте локально с низким лимитом (например, 5 запросов/мин) и проверяйте ответ с текстом “API calls quota exceeded” или кодом 429.
- Проверьте работу заголовков прокси (RealIpHeader). Без корректного заголовка все запросы будут считаться от одного IP.
Когда ограничение частоты не помогает (примеры ошибок)
- Направленные DDoS-атаки на уровне сети (Layer 3/4) всё равно нужно блокировать на сетевом/облачном уровне.
- Если злоумышленник использует пул прокси/большое количество IP, ограничение по IP может быть обойдёно.
- При отсутствии распределённого счётчика в кластере инстансы будут считать лимиты отдельно и фактически разрешат гораздо больше запросов.
Альтернативные подходы
- Ограничение по API-ключу/ClientId — надёжнее для API с ключами аутентификации.
- Токены JWT с учётом метаданных (rate limits в токене) для отдельных пользователей.
- Использование WAF или облачного rate limiting (Cloud provider), чтобы отсеять часть трафика до приложения.
Поддержка Redis (распределённое хранилище)
При горизонтальном масштабировании используйте Redis для хранения счётчиков. Пакет AspNetCoreRateLimit поддерживает распределённые хранилища. Общая идея:
- Подключить клиент Redis (StackExchange.Redis или аналог).
- Зарегистрировать реализацию хранилища счётчиков, основанную на Redis.
- Обновить конфигурацию для использования этого хранилища.
Этот шаг убирает проблему “каждый инстанс — свои счётчики” и делает лимитирование корректным в кластере.
Мини-SOP: развертывание rate limiting в проде
- Установите пакет AspNetCoreRateLimit в тестовом окружении.
- Добавьте базовую конфигурацию в appsettings.Development.json с очень низким лимитом для тестов.
- Протестируйте сценарии: легитимный трафик, повторяющиеся запросы, поведение прокси.
- Перенесите конфигурацию в staging и включите логи и метрики.
- На проде используйте плавный rollout: включайте middleware для части трафика, мониторьте 429 и пользовательские ошибки.
- При масштабировании подключите Redis и повторно протестируйте.
Роль-зависимые чеклисты
Разработчик API:
- Проверить, какие эндпоинты тяжёлые по CPU/IO.
- Предложить отдельные лимиты для таких эндпоинтов.
- Добавить понятное сообщение об ошибке при 429.
DevOps/Инфраструктура:
- Настроить Redis/распределённое хранилище при кластеризации.
- Настроить мониторинг (метрики 429, количество отклонённых IP).
- Проверить заголовки прокси и балансировщика.
Команда безопасности:
- Проанализировать сценарии обхода ограничений/IP-пула.
- Включить правила WAF при необходимости.
Критерии приёмки
- 429 возвращается при превышении лимита.
- Локальные тесты с низким лимитом подтверждают работу middleware.
- При балансировке нагрузки и включённом Redis счётчики синхронизированы между инстансами.
- Метрические алерты срабатывают при всплесках 429 или аномальном количестве отклонённых запросов.
Тестовые сценарии (acceptance)
- Отправить N запросов в период P и ожидать первые M успешных, затем 429.
- Проверить, что endpoint whitelist пропускает запросы без 429.
- Проверить, что ip whitelist и client whitelist работают.
- Тест прокси: запросы через обратный прокси с корректным X-Real-IP — каждый IP лимитируется отдельно.
Отладка и распространённые проблемы
Проблема: все пользователи получают одинаковые лимиты.
- Причина: обратный прокси не передаёт заголовок X-Real-IP. Решение: настроить прокси так, чтобы он пробрасывал реальный IP или используйте другой заголовок.
Проблема: при масштабировании лимиты становятся мягче.
- Причина: счётчики в памяти у разных инстансов. Решение: переключиться на Redis.
Проблема: слишком много false-positive 429 для легитимных клиентов.
- Причина: правила слишком жёсткие или StackBlockedRequests неправильно настроен. Решение: смягчить правила, добавить whitelist для доверенных клиентов.
Примеры полезных правил
- Короткие окна для предотвращения всплесков: “1s” -> 5 запросов.
- Длинные окна для общего ограничения: “1h” -> 1000 запросов.
- Отдельные правила для платных/авторизованных клиентов.
Безопасность и приватность
- Не храните в логах чувствительные клиентские данные.
- Следите за GDPR/локальными правилами при логировании IP, если это применимо в вашей юрисдикции.
Короткая сводка
Ограничение частоты запросов — обязательный элемент зрелой архитектуры публичного API. Оно помогает контролировать ресурсопотребление, снижать риск сервисных отказов и управлять злоупотреблениями. Для ASP.NET Core удобен пакет AspNetCoreRateLimit, но при горизонтальном масштабировании обязательно используйте распределённое хранилище счётчиков.
Дополнительные материалы и что проверить дальше
- Документация пакета AspNetCoreRateLimit для продвинутых сценариев.
- Варианты интеграции с облачными WAF/Rate Limit от провайдера.
- Мониторинг и алерты на основе метрик 429 и throttled requests.
Короткие выводы
- Включите базовое ограничение запросов даже для внутренних сервисов.
- Для API с ключами используйте идентификацию по ClientId/API Key.
- При использовании балансировщика — распределённое хранилище счётчиков (Redis).