asp.net-core
Kursbegränsning
Sök…
Anmärkningar
AspNetCoreRateLimit är en ASP.NET-kärnhastighetsbegränsande lösning med öppen källkod som är utformad för att kontrollera frekvensen för förfrågningar som klienter kan göra till en webb-API eller MVC-app baserad på IP-adress eller klient-ID.
Kursbegränsning baserad på klientens IP
Med IpRateLimit mellanprogram kan du ställa in flera gränser för olika scenarier som att låta ett IP- eller IP-intervall göra ett maximalt antal samtal i ett tidsintervall som per sekund, 15 minuter osv. Du kan definiera dessa gränser för att adressera alla förfrågningar som görs till API eller så kan du gränserna för varje URL-sökväg eller HTTP-verb och sökväg.
Uppstart
NuGet installera :
Install-Package AspNetCoreRateLimit
Startup.cs-kod :
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(); }
Du bör registrera mellanprogrammet före andra komponenter utom loggerFactory.
om du laddar balansera din app måste du använda IDistributedCache
med Redis eller SQLServer så att alla kestrel-instanser kommer att ha samma hastighetsgränslagring. Istället för i minnesbutikerna bör du injicera de distribuerade butikerna så här:
// inject counter and rules distributed cache stores services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Konfiguration och allmänna regler 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 } ] }
Om EnableEndpointRateLimiting
är inställd på false
kommer gränserna att gälla globalt och endast regler som har som slutpunkt *
kommer att gälla. Om du till exempel ställer in en gräns på 5 samtal per sekund räknas alla HTTP-samtal till någon slutpunkt till den gränsen.
Om EnableEndpointRateLimiting
är satt till true
kommer gränserna att gälla för varje slutpunkt som i {HTTP_Verb}{PATH}
. Om du till exempel ställer in en gräns på 5 samtal per sekund för *:/api/values
en klient ringa GET /api/values
5 gånger per sekund men också 5 gånger PUT /api/values
.
Om StackBlockedRequests
är inställd på false
avvisade samtal läggs inte till gasreglaget. Om en klient gör tre förfrågningar per sekund och du har ställt in en gräns för ett samtal per sekund, kommer andra gränser som per minut eller per dagräknare bara att spela in det första samtalet, det som inte var blockerat. Om du vill avvisa förfrågningar om att räkna mot de andra gränserna måste du ställa StackBlockedRequests
till true
.
RealIpHeader
används för att extrahera klientens IP när din Kestrel-server ligger bakom en omvänd proxy, om din proxy använder en annan rubrik använder X-Real-IP
detta alternativ för att ställa in den.
ClientIdHeader
används för att extrahera klient-id för vit listning, om ett klient-id finns i denna rubrik och matchar ett värde som anges i ClientWhitelist tillämpas inga hastighetsgränser.
Överträffa allmänna regler för specifika 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-fältet stöder IP v4- och v6-värden och sträcker sig som "192.168.0.0/24", "fe80 :: / 10" eller "192.168.0.0-192.168.0.255".
Definiera regler för gränsvärden
En regel består av ett slutpunkt, en period och en gräns.
Endpoint format är {HTTP_Verb}:{PATH}
, du kan rikta in dig på alla HTTP-verb med asterix-symbolen.
Periodformat är {INT}{PERIOD_TYPE}
, du kan använda en av följande periodtyper: s, m, h, d
.
Begränsningsformatet är {LONG}
.
Exempel :
Betygsätt gränsen för alla slutpunkter till 2 samtal per sekund:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Om du från samma IP på samma sekund tar 3 GET-samtal till api / värden blockeras det senaste samtalet. Men om du på samma sekund som du kallar PUT api / värden, kommer förfrågan att gå igenom eftersom det är en annan slutpunkt. När slutpunktsbegränsning är aktiverad är varje samtal hastighetsbegränsad baserat på {HTTP_Verb}{PATH}
.
Betygsätt gränssamtal med HTTP-verb till /api/values
till 5 samtal per 15 minuter:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Betygsgräns GET samtal till /api/values
till 5 samtal per timme:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Om du från samma IP på en timme kommer att ringa 6 GET-samtal till api / värden blockeras det senaste samtalet. Men om du på samma timme som du kallar GET api / Values / 1 också kommer förfrågan att gå igenom eftersom det är en annan slutpunkt.
Beteende
När en klient ringer ett HTTP-samtal gör IpRateLimitMiddleware följande:
- extraherar IP, klient-id, HTTP-verb och URL från förfrågningsobjektet, om du vill implementera din egen extraktionslogik kan du åsidosätta
IpRateLimitMiddleware.SetIdentity
- söker efter IP, klient-id och URL i de vita listorna, om några matchningar görs ingen åtgärd
- sökningar i IP-reglerna för en matchning, alla regler som gäller grupperas efter period, för varje period används den mest restriktiva regeln
- sökningar i de allmänna reglerna för en matchning, om en allmän regel som matchar har en definierad period som inte finns i IP-reglerna används denna allmänna regel också
- för varje matchningsregel ökas hastighetsgränsräknaren, om räknarvärdet är större, då regelgränsen så blir begäran blockerad
Om förfrågan blockeras får klienten ett SMS-svar som detta:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Du kan anpassa svaret genom att ändra dessa alternativ HttpStatusCode
och QuotaExceededMessage
, om du vill implementera ditt eget svar kan du åsidosätta IpRateLimitMiddleware.ReturnQuotaExceededResponse
. Retry-After
rubrikvärdet uttrycks i sekunder.
Om begäran inte får begränsad hastighet används den längsta perioden som definieras i matchningsreglerna för att komponera X-Rate-Limit-rubrikerna, de här rubrikerna injiceras i svaret:
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
Som standard loggas begäran loggas med Microsoft.Extensions.Logging.ILogger
, om du vill implementera din egen loggning kan du åsidosätta IpRateLimitMiddleware.LogBlockedRequest
. Standardloggern avger följande information när en begäran blir hastighetsbegränsad:
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.
Uppdateringsfrekvensgränser vid körning
Vid programstart laddas reglerna för IP-hastighetsgränser som definieras i appsettings.json
i cache av antingen MemoryCacheClientPolicyStore
eller DistributedCacheIpPolicyStore
beroende på vilken typ av cache-leverantör du använder. Du kan komma åt Ip-policylagret i en controller och ändra IP-reglerna så:
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); } }
På så sätt kan du lagra IP-hastighetsgränserna i en databas och trycka dem i cache efter varje appstart.
Kursbegränsning baserad på klient-ID
Med ClientRateLimit mellanprogram kan du ställa in flera gränser för olika scenarier som att låta en klient göra ett maximalt antal samtal i ett tidsintervall som per sekund, 15 minuter osv. Du kan definiera dessa gränser för att adressera alla förfrågningar till ett API eller du kan gränserna för varje URL-sökväg eller HTTP-verb och sökväg.
Uppstart
NuGet installera :
Install-Package AspNetCoreRateLimit
Startup.cs-kod :
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(); }
Du bör registrera mellanprogrammet före andra komponenter utom loggerFactory.
om du laddar balansera din app måste du använda IDistributedCache
med Redis eller SQLServer så att alla kestrel-instanser kommer att ha samma hastighetsgränslagring. Istället för i minnesbutikerna bör du injicera de distribuerade butikerna så här:
// inject counter and rules distributed cache stores services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Konfiguration och allmänna regler 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 } ] }
Om EnableEndpointRateLimiting
är inställd på false
kommer gränserna att gälla globalt och endast regler som har som slutpunkt *
kommer att gälla. Om du till exempel ställer in en gräns på 5 samtal per sekund räknas alla HTTP-samtal till någon slutpunkt till den gränsen.
Om EnableEndpointRateLimiting
är satt till true
kommer gränserna att gälla för varje slutpunkt som i {HTTP_Verb}{PATH}
. Om du till exempel ställer in en gräns på 5 samtal per sekund för *:/api/values
en klient ringa GET /api/values
5 gånger per sekund men också 5 gånger PUT /api/values
.
Om StackBlockedRequests
är inställd på false
avvisade samtal läggs inte till gasreglaget. Om en klient gör tre förfrågningar per sekund och du har ställt in en gräns för ett samtal per sekund, kommer andra gränser som per minut eller per dagräknare bara att spela in det första samtalet, det som inte var blockerat. Om du vill avvisa förfrågningar om att räkna mot de andra gränserna måste du ställa StackBlockedRequests
till true
.
ClientIdHeader
används för att extrahera klient-ID, om ett klient-id finns i denna rubrik och matchar ett värde som anges i ClientWhitelist tillämpas inga taktränser.
Överträffa allmänna regler för specifika klientappsettings.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 } ] } ] }
Definiera regler för gränsvärden
En regel består av ett slutpunkt, en period och en gräns.
Endpoint format är {HTTP_Verb}:{PATH}
, du kan rikta in dig på alla HTTP-verb med asterix-symbolen.
Periodformat är {INT}{PERIOD_TYPE}
, du kan använda en av följande periodtyper: s, m, h, d
.
Begränsningsformatet är {LONG}
.
Exempel :
Betygsätt gränsen för alla slutpunkter till 2 samtal per sekund:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Om en klient ringer 3 GET-samtal på api / värden på samma sekund kommer det senaste samtalet att blockeras. Men om han på samma sekund också kallar PUT api / värden, kommer förfrågan att gå igenom eftersom det är en annan slutpunkt. När slutpunktsbegränsning är aktiverad är varje samtal hastighetsbegränsad baserat på {HTTP_Verb}{PATH}
.
Betygsätt gränssamtal med HTTP-verb till /api/values
till 5 samtal per 15 minuter:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Betygsgräns GET samtal till /api/values
till 5 samtal per timme:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Om en klient ringer 6 GET-samtal på api / värden på en timme kommer det senaste samtalet att blockeras. Men om han på samma timme också kallar GET api / Values / 1, kommer förfrågan att gå igenom eftersom det är en annan slutpunkt.
Beteende
När en klient ringer ett HTTP-samtal gör ClientRateLimitMiddleware följande:
- extraherar klient-ID, HTTP-verb och URL från förfrågningsobjektet, om du vill implementera din egen extraktionslogik kan du åsidosätta
ClientRateLimitMiddleware.SetIdentity
- söker efter klient-ID och URL i de vita listorna, om några matchningar görs ingen åtgärd
- sökningar i klientens regler för en matchning, alla regler som gäller grupperas efter period, för varje period används den mest restriktiva regeln
- sökningar i de allmänna reglerna för en match, om en allmän regel som matchar har en definierad period som inte finns i klientreglerna, används denna allmänna regel också
- för varje matchningsregel ökas hastighetsgränsräknaren, om räknarvärdet är större, då regelgränsen så blir begäran blockerad
Om förfrågan blockeras får klienten ett SMS-svar som detta:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Du kan anpassa svaret genom att ändra dessa alternativ HttpStatusCode
och QuotaExceededMessage
, om du vill implementera ditt eget svar kan du åsidosätta ClientRateLimitMiddleware.ReturnQuotaExceededResponse
. Retry-After
rubrikvärdet uttrycks i sekunder.
Om begäran inte får begränsad hastighet används den längsta perioden som definieras i matchningsreglerna för att komponera X-Rate-Limit-rubrikerna, de här rubrikerna injiceras i svaret:
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
Som standard loggas förfrågan loggas med Microsoft.Extensions.Logging.ILogger
, om du vill implementera din egen loggning kan du åsidosätta ClientRateLimitMiddleware.LogBlockedRequest
. Standardloggern avger följande information när en begäran blir hastighetsbegränsad:
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.
Uppdateringsfrekvensgränser vid körning
Vid programstart laddas appsettings.json
definieras i appsettings.json
i cache av antingen MemoryCacheClientPolicyStore
eller DistributedCacheClientPolicyStore
beroende på vilken typ av cache-leverantör du använder. Du kan komma åt kundpolicyn i en controller och ändra reglerna så:
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); } }
På det här sättet kan du lagra klientfrekvensgränserna i en databas och skjuta dem i cache efter varje appstart.