asp.net-core
Ограничение скорости
Поиск…
замечания
AspNetCoreRateLimit - это приложение для ограничения скорости передачи данных с открытым исходным кодом ASP.NET Core, предназначенное для контроля скорости запросов, которые клиенты могут сделать в веб-API или приложении MVC на основе IP-адреса или идентификатора клиента.
Ограничение скорости на основе IP-адреса клиента
С помощью промежуточного программного обеспечения IpRateLimit вы можете установить несколько ограничений для разных сценариев, например, разрешить IP или IP-диапазону делать максимальное количество вызовов за такой промежуток времени, как в секунду, 15 минут и т. Д. Вы можете определить эти лимиты для решения всех запросов, сделанных для API или вы можете ограничить пределы для каждого пути URL или HTTP-глагола и пути.
Настроить
Установка NuGet :
Install-Package AspNetCoreRateLimit
Код запуска :
public void ConfigureServices(IServiceCollection services) { // 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<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")); //load ip rules from appsettings.json services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies")); // inject counter and rules stores services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIpRateLimiting(); app.UseMvc(); }
Вы должны зарегистрировать промежуточное программное обеспечение перед любыми другими компонентами, кроме loggerFactory.
если вы загружаете баланс своего приложения, вам нужно будет использовать IDistributedCache
с Redis или SQLServer, чтобы все экземпляры IDistributedCache
имели одинаковое хранилище ограничений скорости. Вместо хранилищ в памяти вы должны вводить распределенные хранилища следующим образом:
// inject counter and rules distributed cache stores services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Конфигурация и общие правила appsettings.json :
"IpRateLimiting": { "EnableEndpointRateLimiting": false, "StackBlockedRequests": false, "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
установлено значение false
то ограничения будут применяться в глобальном масштабе, и будут применяться только правила, имеющие конечную точку *
. Например, если вы установите ограничение в 5 вызовов в секунду, любой HTTP-вызов любой конечной точки будет учитываться в этом пределе.
Если для параметра EnableEndpointRateLimiting
установлено значение true
ограничения будут применяться для каждой конечной точки, как в {HTTP_Verb}{PATH}
. Например, если вы устанавливаете ограничение в 5 вызовов в секунду для *:/api/values
клиент может вызывать GET /api/values
5 раз в секунду, а также 5 раз PUT /api/values
.
Если для StackBlockedRequests
установлено значение false
отклоненные вызовы не добавляются в счетчик дроссельной заслонки. Если клиент делает 3 запроса в секунду, и вы установили ограничение на один вызов в секунду, другие лимиты, такие как счетчики на минуту или день, будут записывать только первый вызов, тот, который не был заблокирован. Если вы хотите, чтобы отклоненные запросы StackBlockedRequests
в других пределах, вам необходимо установить значение StackBlockedRequests
в true
.
RealIpHeader
используется для извлечения клиентского IP- RealIpHeader
когда ваш сервер Kestrel находится за обратным прокси-сервером, если ваш прокси использует другой заголовок, тогда X-Real-IP
использует этот параметр для его настройки.
ClientIdHeader
используется для извлечения идентификатора клиента для белого листинга, если идентификатор клиента присутствует в этом заголовке и соответствует значению, указанному в ClientWhitelist, тогда не применяются ограничения по скорости.
Переопределить общие правила для определенных IP-адресов appsettings.json :
"IpRateLimitPolicies": { "IpRules": [ { "Ip": "84.247.85.224", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 10 }, { "Endpoint": "*", "Period": "15m", "Limit": 200 } ] }, { "Ip": "192.168.3.22/25", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 }, { "Endpoint": "*", "Period": "15m", "Limit": 150 }, { "Endpoint": "*", "Period": "12h", "Limit": 500 } ] } ] }
Поле IP поддерживает значения IP v4 и v6 и диапазоны, такие как «192.168.0.0/24», «fe80 :: / 10» или «192.168.0.0-192.168.0.255».
Определение правил ограничения ставок
Правило состоит из конечной точки, периода и предела.
Формат {HTTP_Verb}:{PATH}
точки {HTTP_Verb}:{PATH}
, вы можете настроить таргетинг на любой HTTP-глагол, используя символ asterix.
Формат периода: {INT}{PERIOD_TYPE}
, вы можете использовать один из следующих типов периодов: s, m, h, d
.
Предельный формат - {LONG}
.
Примеры :
Скорость ограничивает все конечные точки до 2 вызовов в секунду:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Если с одного и того же IP-адреса в течение одной секунды вы сделаете 3 вызова GET для api / values, последний вызов будет заблокирован. Но если в течение той же секунды вы также вызываете PUT api / values, запрос будет проходить, потому что это другая конечная точка. Когда ограничение скорости конечной точки включено, каждый вызов ограничивается скоростью на основе {HTTP_Verb}{PATH}
.
Ограничение скорости звонка с любыми HTTP-глаголами to /api/values
до 5 вызовов за 15 минут:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Ограничение скорости GET вызов /api/values
до 5 вызовов в час:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Если с одного и того же IP-адреса за один час вы сделаете 6 GET-вызовов для api / values, последний звонок будет заблокирован. Но если в тот же час вы вызываете GET api / values / 1, запрос будет проходить, потому что это другая конечная точка.
Поведение
Когда клиент делает HTTP-вызов, IpRateLimitMiddleware делает следующее:
- извлекает IP-адрес, идентификатор клиента, HTTP-глагол и URL-адрес из объекта запроса, если вы хотите реализовать свою собственную логику извлечения, вы можете переопределить
IpRateLimitMiddleware.SetIdentity
- ищет IP-адрес, идентификатор клиента и URL-адрес в белых списках, если какие-либо совпадения, то никаких действий не предпринимается
- поиск в правилах IP для соответствия, все применяемые правила группируются по периоду, для каждого периода используется наиболее ограничивающее правило
- ищет в общих правилах для соответствия, если общее правило, которое соответствует, имеет определенный период, отсутствующий в правилах IP, тогда это общее правило также используется
- для каждого правила сопоставления счетчик ограничения скорости увеличивается, если значение счетчика больше, чем предел правила, тогда запрос блокируется
Если запрос блокируется, клиент получает текстовый ответ следующим образом:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Вы можете настроить ответ, изменив эти параметры HttpStatusCode
и QuotaExceededMessage
, если вы хотите реализовать свой собственный ответ, вы можете переопределить IpRateLimitMiddleware.ReturnQuotaExceededResponse
. Значение заголовка Retry-After
выражается в секундах.
Если запрос не получает ограничение по скорости, то самый длинный период, определенный в правилах сопоставления, используется для составления заголовков X-Rate-Limit, эти заголовки вводятся в ответ:
X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)
X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets
По умолчанию заблокированный запрос регистрируется с помощью Microsoft.Extensions.Logging.ILogger
, если вы хотите реализовать свой собственный журнал, вы можете переопределить IpRateLimitMiddleware.LogBlockedRequest
. Регистратор по умолчанию генерирует следующую информацию, когда запрос получает ограничение по скорости:
info: AspNetCoreRateLimit.IpRateLimitMiddleware[0]
Request get:/api/values from IP 84.247.85.224 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
Ограничения скорости обновления во время выполнения
При запуске приложения правила ограничения скорости IP, определенные в appsettings.json
, загружаются в кеш либо MemoryCacheClientPolicyStore
либо DistributedCacheIpPolicyStore
зависимости от того, какой тип поставщика кеша вы используете. Вы можете получить доступ к хранилищу политик Ip внутри контроллера и изменить правила IP следующим образом:
public class IpRateLimitController : Controller { private readonly IpRateLimitOptions _options; private readonly IIpPolicyStore _ipPolicyStore; public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore) { _options = optionsAccessor.Value; _ipPolicyStore = ipPolicyStore; } [HttpGet] public IpRateLimitPolicies Get() { return _ipPolicyStore.Get(_options.IpPolicyPrefix); } [HttpPost] public void Post() { var pol = _ipPolicyStore.Get(_options.IpPolicyPrefix); pol.IpRules.Add(new IpRateLimitPolicy { Ip = "8.8.4.4", Rules = new List<RateLimitRule>(new RateLimitRule[] { new RateLimitRule { Endpoint = "*:/api/testupdate", Limit = 100, Period = "1d" } }) }); _ipPolicyStore.Set(_options.IpPolicyPrefix, pol); } }
Таким образом, вы можете сохранить ограничения скорости IP в базе данных и вставить их в кеш после каждого запуска приложения.
Ограничение скорости на основе идентификатора клиента
С промежуточным программным обеспечением ClientRateLimit вы можете установить несколько ограничений для разных сценариев, таких как предоставление клиенту максимального количества вызовов за такой промежуток времени, как в секунду, 15 минут и т. Д. Вы можете определить эти ограничения для адресации всех запросов, сделанных в API, или вы может ограничивать пределы для каждого пути URL или HTTP-глагола и пути.
Настроить
Установка NuGet :
Install-Package AspNetCoreRateLimit
Код запуска :
public void ConfigureServices(IServiceCollection services) { // 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<ClientRateLimitOptions>(Configuration.GetSection("ClientRateLimiting")); //load client rules from appsettings.json services.Configure<ClientRateLimitPolicies>(Configuration.GetSection("ClientRateLimitPolicies")); // inject counter and rules stores services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseClientRateLimiting(); app.UseMvc(); }
Вы должны зарегистрировать промежуточное программное обеспечение перед любыми другими компонентами, кроме loggerFactory.
если вы загружаете баланс своего приложения, вам нужно будет использовать IDistributedCache
с Redis или SQLServer, чтобы все экземпляры IDistributedCache
имели одинаковое хранилище ограничений скорости. Вместо хранилищ в памяти вы должны вводить распределенные хранилища следующим образом:
// inject counter and rules distributed cache stores services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Конфигурация и общие правила appsettings.json :
"ClientRateLimiting": { "EnableEndpointRateLimiting": false, "StackBlockedRequests": false, "ClientIdHeader": "X-ClientId", "HttpStatusCode": 429, "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
установлено значение false
то ограничения будут применяться в глобальном масштабе, и будут применяться только правила, имеющие конечную точку *
. Например, если вы установите ограничение в 5 вызовов в секунду, любой HTTP-вызов любой конечной точки будет учитываться в этом пределе.
Если для параметра EnableEndpointRateLimiting
установлено значение true
ограничения будут применяться для каждой конечной точки, как в {HTTP_Verb}{PATH}
. Например, если вы устанавливаете ограничение в 5 вызовов в секунду для *:/api/values
клиент может вызывать GET /api/values
5 раз в секунду, а также 5 раз PUT /api/values
.
Если для StackBlockedRequests
установлено значение false
отклоненные вызовы не добавляются в счетчик дроссельной заслонки. Если клиент делает 3 запроса в секунду, и вы установили ограничение на один вызов в секунду, другие лимиты, такие как счетчики на минуту или день, будут записывать только первый вызов, тот, который не был заблокирован. Если вы хотите, чтобы отклоненные запросы StackBlockedRequests
в других пределах, вам необходимо установить значение StackBlockedRequests
в true
.
ClientIdHeader
используется для извлечения идентификатора клиента, если идентификатор клиента присутствует в этом заголовке и соответствует значению, указанному в ClientWhitelist, тогда не применяются ограничения по скорости.
Переопределить общие правила для определенных клиентов appsettings.json :
"ClientRateLimitPolicies": { "ClientRules": [ { "ClientId": "client-id-1", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 10 }, { "Endpoint": "*", "Period": "15m", "Limit": 200 } ] }, { "Client": "client-id-2", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 }, { "Endpoint": "*", "Period": "15m", "Limit": 150 }, { "Endpoint": "*", "Period": "12h", "Limit": 500 } ] } ] }
Определение правил ограничения ставок
Правило состоит из конечной точки, периода и предела.
Формат {HTTP_Verb}:{PATH}
точки {HTTP_Verb}:{PATH}
, вы можете настроить таргетинг на любой HTTP-глагол, используя символ asterix.
Формат периода: {INT}{PERIOD_TYPE}
, вы можете использовать один из следующих типов периодов: s, m, h, d
.
Предельный формат - {LONG}
.
Примеры :
Скорость ограничивает все конечные точки до 2 вызовов в секунду:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Если в течение той же секунды клиент сделает 3 GET-вызова api / values, последний вызов будет заблокирован. Но если в течение той же секунды он вызывает PUT api / values, запрос будет проходить, потому что это другая конечная точка. Когда ограничение скорости конечной точки включено, каждый вызов ограничивается скоростью на основе {HTTP_Verb}{PATH}
.
Ограничение скорости звонка с любыми HTTP-глаголами to /api/values
до 5 вызовов за 15 минут:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Ограничение скорости GET вызов /api/values
до 5 вызовов в час:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Если через час клиент совершит 6 GET-вызовов для api / values, последний звонок будет заблокирован. Но если в тот же час он называет GET api / values / 1, запрос будет проходить, потому что это другая конечная точка.
Поведение
Когда клиент делает HTTP-вызов, ClientRateLimitMiddleware делает следующее:
- извлекает идентификатор клиента, HTTP-глагол и URL-адрес из объекта запроса, если вы хотите реализовать свою собственную логику извлечения, вы можете переопределить
ClientRateLimitMiddleware.SetIdentity
- ищет идентификаторы и URL-адреса Клиента в белых списках, если какие-либо совпадения, то никаких действий не предпринимается
- поиск в правилах Клиента для соответствия, все применяемые правила сгруппированы по периоду, за каждый период используется наиболее ограничительное правило
- выполняет поиск в общих правилах для соответствия, если общее правило, которое соответствует, имеет определенный период, отсутствующий в правилах Клиента, тогда это общее правило также используется
- для каждого правила сопоставления счетчик ограничения скорости увеличивается, если значение счетчика больше, чем предел правила, тогда запрос блокируется
Если запрос блокируется, клиент получает текстовый ответ следующим образом:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Вы можете настроить ответ, изменив эти параметры HttpStatusCode
и QuotaExceededMessage
, если вы хотите реализовать свой собственный ответ, вы можете переопределить ClientRateLimitMiddleware.ReturnQuotaExceededResponse
. Значение заголовка Retry-After
выражается в секундах.
Если запрос не получает ограничение по скорости, то самый длинный период, определенный в правилах сопоставления, используется для составления заголовков X-Rate-Limit, эти заголовки вводятся в ответ:
X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)
X-Rate-Limit-Remaining: number of request remaining
X-Rate-Limit-Reset: UTC date time when the limits resets
По умолчанию заблокированный запрос регистрируется с помощью Microsoft.Extensions.Logging.ILogger
, если вы хотите реализовать свой собственный журнал, вы можете переопределить ClientRateLimitMiddleware.LogBlockedRequest
. Регистратор по умолчанию генерирует следующую информацию, когда запрос получает ограничение по скорости:
info: AspNetCoreRateLimit.ClientRateLimitMiddleware[0]
Request get:/api/values from ClientId client-id-1 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
Ограничения скорости обновления во время выполнения
При запуске приложения правила ограничения скорости клиента, определенные в appsettings.json
, загружаются в кеш либо MemoryCacheClientPolicyStore
либо DistributedCacheClientPolicyStore
зависимости от того, какой тип поставщика кеша вы используете. Вы можете получить доступ к хранилищу политик клиента внутри контроллера и изменить правила следующим образом:
public class ClientRateLimitController : Controller { private readonly ClientRateLimitOptions _options; private readonly IClientPolicyStore _clientPolicyStore; public ClientRateLimitController(IOptions<ClientRateLimitOptions> optionsAccessor, IClientPolicyStore clientPolicyStore) { _options = optionsAccessor.Value; _clientPolicyStore = clientPolicyStore; } [HttpGet] public ClientRateLimitPolicy Get() { return _clientPolicyStore.Get($"{_options.ClientPolicyPrefix}_cl-key-1"); } [HttpPost] public void Post() { var id = $"{_options.ClientPolicyPrefix}_cl-key-1"; var clPolicy = _clientPolicyStore.Get(id); clPolicy.Rules.Add(new RateLimitRule { Endpoint = "*/api/testpolicyupdate", Period = "1h", Limit = 100 }); _clientPolicyStore.Set(id, clPolicy); } }
Таким образом, вы можете хранить лимиты ставок клиента в базе данных и вставлять их в кеш после каждого запуска приложения.