asp.net-core
Ratenbegrenzung
Suche…
Bemerkungen
AspNetCoreRateLimit ist eine Open Source-Lösung zur ASP.NET-Kernratenbegrenzung, mit der die Rate der Anforderungen gesteuert wird, die Clients an eine Web-API oder MVC-App basierend auf der IP-Adresse oder der Client-ID richten können.
Ratenbegrenzung basierend auf der Client-IP
Mit der IpRateLimit-Middleware können Sie mehrere Grenzwerte für verschiedene Szenarien festlegen, z. B. das Zulassen einer maximalen Anzahl von Anrufen in einem Zeitintervall (z. B. pro Sekunde, 15 Minuten usw.) für einen IP- oder IP-Bereich API oder Sie können die Grenzen für jeden URL-Pfad oder jedes HTTP-Verb und -Pfad festlegen.
Konfiguration
NuGet installieren :
Install-Package AspNetCoreRateLimit
Startup.cs-Code :
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(); }
Sie sollten die Middleware vor allen anderen Komponenten außer loggerFactory registrieren.
Wenn Sie die App für die IDistributedCache
laden, müssen Sie IDistributedCache
mit Redis oder SQLServer verwenden, damit alle Kestrel-Instanzen denselben Speicher für die IDistributedCache
haben. Anstelle der im Speicher befindlichen Speicher sollten Sie die verteilten Speicher wie folgt einfügen:
// inject counter and rules distributed cache stores services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Konfiguration und allgemeine Regeln 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 } ] }
Wenn für EnableEndpointRateLimiting
false
EnableEndpointRateLimiting
ist, gelten die Grenzwerte global und es gelten nur Regeln mit dem Endpunkt *
. Wenn Sie beispielsweise ein Limit von 5 Anrufen pro Sekunde festlegen, wird jeder HTTP-Anruf an einem Endpunkt für dieses Limit gezählt.
Wenn EnableEndpointRateLimiting
auf true
gesetzt ist, true
die Grenzwerte für jeden Endpunkt wie in {HTTP_Verb}{PATH}
. Wenn Sie beispielsweise ein Limit von 5 Anrufen pro Sekunde für *:/api/values
ein Client GET /api/values
5-mal pro Sekunde, aber auch 5-mal PUT /api/values
aufrufen.
Wenn StackBlockedRequests
auf false
gesetzt ist, werden abgelehnte Aufrufe nicht zum StackBlockedRequests
hinzugefügt. Wenn ein Client drei Anfragen pro Sekunde abarbeitet und Sie ein Limit von einem Anruf pro Sekunde festgelegt haben, werden andere Grenzwerte wie Minuten pro Tag oder pro Tag nur den ersten Anruf aufzeichnen, der nicht gesperrt ist. Wenn abgelehnte Anforderungen für die anderen Grenzwerte StackBlockedRequests
werden sollen, müssen Sie StackBlockedRequests
auf true
.
Der RealIpHeader
wird verwendet, um die Client-IP- RealIpHeader
zu extrahieren, wenn sich Ihr Kestrel-Server hinter einem Reverse-Proxy befindet. Wenn Ihr Proxy-Server einen anderen Header verwendet, verwenden Sie X-Real-IP
Konfigurieren dieser Option.
Der ClientIdHeader
wird zum Extrahieren der Client-ID für das ClientIdHeader
verwendet. Wenn in diesem Header eine Client-ID vorhanden ist, die mit einem in ClientWhitelist angegebenen Wert übereinstimmt, werden keine Ratenbegrenzungen angewendet.
Überschreiben Sie allgemeine Regeln für bestimmte IPs 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 } ] } ] }
Das IP-Feld unterstützt IP v4- und v6-Werte und Bereiche wie "192.168.0.0/24", "fe80 :: / 10" oder "192.168.0.0-192.168.0.255".
Ratenlimitregeln definieren
Eine Regel besteht aus einem Endpunkt, einer Periode und einem Limit.
Das Endpunktformat ist {HTTP_Verb}:{PATH}
. Sie können ein beliebiges HTTP-Verb mithilfe des Sternsymbols anvisieren.
Das Periodenformat ist {INT}{PERIOD_TYPE}
. Sie können einen der folgenden Periodentypen verwenden: s, m, h, d
.
Das Limitformat ist {LONG}
.
Beispiele :
Ratenbeschränkung für alle Endpunkte auf 2 Anrufe pro Sekunde:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Wenn Sie von derselben IP-Adresse aus in derselben Sekunde 3 GET-Aufrufe von API / Werten durchführen, wird der letzte Anruf blockiert. Wenn Sie jedoch in derselben Sekunde auch PUT-Werte / -werte aufrufen, wird die Anforderung durchlaufen, da es sich um einen anderen Endpunkt handelt. Wenn die Begrenzung der Endpunktrate aktiviert ist, ist jeder Anruf basierend auf {HTTP_Verb}{PATH}
auf die Rate begrenzt.
Begrenzen Sie die Anzahl der Anrufe mit einem beliebigen HTTP-Verb auf /api/values
auf 5 Aufrufe pro 15 Minuten:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Ratenlimit GET-Aufruf an /api/values
auf 5 Anrufe pro Stunde:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Wenn Sie innerhalb einer Stunde von derselben IP-Adresse aus 6 GET-Anrufe an API / Werte tätigen, wird der letzte Anruf blockiert. Wenn Sie jedoch in derselben Stunde auch GET api / values / 1 aufrufen, wird die Anforderung durchlaufen, da es sich um einen anderen Endpunkt handelt.
Verhalten
Wenn ein Client einen HTTP-Aufruf durchführt, führt IpRateLimitMiddleware folgende Aktionen aus:
- extrahiert die IP-
IpRateLimitMiddleware.SetIdentity
, die Client-ID, das HTTP-Verb und die URL aus dem Anforderungsobjekt. Wenn Sie Ihre eigene Extraktionslogik implementieren möchten, können SieIpRateLimitMiddleware.SetIdentity
- sucht in den Whitelists nach der IP-Adresse, der Client-ID und der URL. Wenn Übereinstimmung gefunden wird, wird keine Aktion ausgeführt
- Sucht in den IP-Regeln nach einer Übereinstimmung, werden alle anwendbaren Regeln nach Periode gruppiert. Für jede Periode wird die restriktivste Regel verwendet
- Sucht in den Allgemeinen Regeln nach einer Übereinstimmung. Wenn eine übereinstimmende allgemeine Regel einen definierten Zeitraum hat, der nicht in den IP-Regeln enthalten ist, wird diese allgemeine Regel ebenfalls verwendet
- Für jede übereinstimmende Regel wird der Ratenlimitzähler inkrementiert. Wenn der Zählerwert größer als das Regellimit ist, wird die Anforderung blockiert
Wenn die Anfrage blockiert wird, erhält der Client eine Textantwort wie diese:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Sie können die Antwort anpassen, indem Sie diese Optionen HttpStatusCode
und QuotaExceededMessage
. Wenn Sie Ihre eigene Antwort implementieren möchten, können Sie die IpRateLimitMiddleware.ReturnQuotaExceededResponse
. Der Wert für den Retry-After
Header wird in Sekunden angegeben.
Wenn für die Anforderung die Rate nicht begrenzt wird, wird der in den Übereinstimmungsregeln definierte längste Zeitraum zum Erstellen der X-Rate-Limit-Header verwendet. Diese Header werden in die Antwort eingefügt:
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
Standardmäßig werden blockierte Anforderungen mit Microsoft.Extensions.Logging.ILogger
protokolliert. Wenn Sie Ihre eigene Protokollierung implementieren möchten, können Sie IpRateLimitMiddleware.LogBlockedRequest
. Der Standard-Logger gibt die folgenden Informationen aus, wenn für eine Anforderung die Rate begrenzt wird:
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.
Aktualisieren Sie die Ratenlimits zur Laufzeit
Beim Start der Anwendung werden die in appsettings.json
definierten Regeln für die IP- appsettings.json
entweder vom MemoryCacheClientPolicyStore
oder vom DistributedCacheIpPolicyStore
in den Cache geladen, je nachdem, welchen Cache-Provider-Typ Sie verwenden. Sie können auf den IP-Richtlinienspeicher in einem Controller zugreifen und die IP-Regeln wie folgt ändern:
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); } }
Auf diese Weise können Sie die IP-Ratenbegrenzungen in einer Datenbank speichern und nach jedem Start der App im Cache ablegen.
Ratenbegrenzung basierend auf der Client-ID
Mit der Middleware für ClientRateLimit können Sie mehrere Grenzwerte für verschiedene Szenarien festlegen, z. B. die Möglichkeit, dass ein Client in einem Zeitintervall (wie pro Sekunde, 15 Minuten usw.) eine maximale Anzahl von Anrufen durchführt kann die Grenzen für jeden URL-Pfad oder HTTP-Verb und -Pfad festlegen.
Konfiguration
NuGet installieren :
Install-Package AspNetCoreRateLimit
Startup.cs-Code :
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(); }
Sie sollten die Middleware vor allen anderen Komponenten außer loggerFactory registrieren.
Wenn Sie die App für die IDistributedCache
laden, müssen Sie IDistributedCache
mit Redis oder SQLServer verwenden, damit alle Kestrel-Instanzen denselben Speicher für die IDistributedCache
haben. Anstelle der im Speicher befindlichen Speicher sollten Sie die verteilten Speicher wie folgt einfügen:
// inject counter and rules distributed cache stores services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Konfiguration und allgemeine Regeln 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 } ] }
Wenn für EnableEndpointRateLimiting
false
EnableEndpointRateLimiting
ist, gelten die Grenzwerte global und es gelten nur Regeln mit dem Endpunkt *
. Wenn Sie beispielsweise ein Limit von 5 Anrufen pro Sekunde festlegen, wird jeder HTTP-Anruf an einem Endpunkt für dieses Limit gezählt.
Wenn EnableEndpointRateLimiting
auf true
gesetzt ist, true
die Grenzwerte für jeden Endpunkt wie in {HTTP_Verb}{PATH}
. Wenn Sie beispielsweise ein Limit von 5 Anrufen pro Sekunde für *:/api/values
ein Client GET /api/values
5-mal pro Sekunde, aber auch 5-mal PUT /api/values
aufrufen.
Wenn StackBlockedRequests
auf false
gesetzt ist, werden abgelehnte Aufrufe nicht zum StackBlockedRequests
hinzugefügt. Wenn ein Client drei Anfragen pro Sekunde abarbeitet und Sie ein Limit von einem Anruf pro Sekunde festgelegt haben, werden andere Grenzwerte wie Minuten pro Tag oder pro Tag nur den ersten Anruf aufzeichnen, der nicht gesperrt ist. Wenn abgelehnte Anforderungen für die anderen Grenzwerte StackBlockedRequests
werden sollen, müssen Sie StackBlockedRequests
auf true
.
Der ClientIdHeader
wird zum Extrahieren der Client-ID verwendet. Wenn in diesem Header eine Client-ID vorhanden ist, die mit einem in ClientWhitelist angegebenen Wert übereinstimmt, werden keine Ratenbegrenzungen angewendet.
Überschreiben Sie allgemeine Regeln für bestimmte Clients 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 } ] } ] }
Ratenlimitregeln definieren
Eine Regel besteht aus einem Endpunkt, einer Periode und einem Limit.
Das Endpunktformat ist {HTTP_Verb}:{PATH}
. Sie können ein beliebiges HTTP-Verb mithilfe des Sternsymbols anvisieren.
Das Periodenformat ist {INT}{PERIOD_TYPE}
. Sie können einen der folgenden Periodentypen verwenden: s, m, h, d
.
Das Limitformat ist {LONG}
.
Beispiele :
Ratenbeschränkung für alle Endpunkte auf 2 Anrufe pro Sekunde:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Wenn ein Client in derselben Sekunde 3 GET-Aufrufe an API / Werte durchführt, wird der letzte Anruf blockiert. Wenn er jedoch in derselben Sekunde auch PUT-Werte / -werte aufruft, wird die Anforderung durchlaufen, da es sich um einen anderen Endpunkt handelt. Wenn die Begrenzung der Endpunktrate aktiviert ist, ist jeder Anruf basierend auf {HTTP_Verb}{PATH}
auf die Rate begrenzt.
Begrenzen Sie die Anzahl der Anrufe mit einem beliebigen HTTP-Verb auf /api/values
auf 5 Aufrufe pro 15 Minuten:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Ratenlimit GET-Aufruf an /api/values
auf 5 Anrufe pro Stunde:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Wenn ein Client innerhalb einer Stunde 6 GET-Aufrufe an API / Werte durchführt, wird der letzte Anruf blockiert. Wenn er aber in derselben Stunde auch GET api / values / 1 aufruft, wird die Anforderung durchlaufen, da es sich um einen anderen Endpunkt handelt.
Verhalten
Wenn ein Client einen HTTP-Aufruf durchführt, führt die ClientRateLimitMiddleware die folgenden Aktionen aus:
- extrahiert die Client-ID, das HTTP-Verb und die URL aus dem Anforderungsobjekt. Wenn Sie Ihre eigene Extraktionslogik implementieren möchten, können Sie
ClientRateLimitMiddleware.SetIdentity
- Sucht in den Whitelists nach der Client-ID und der URL. Wenn Übereinstimmungen gefunden werden, wird keine Aktion ausgeführt
- Sucht in den Client-Regeln nach einer Übereinstimmung, werden alle geltenden Regeln nach Periode gruppiert. Für jede Periode wird die restriktivste Regel verwendet
- Sucht in den Allgemeinen Regeln nach einer Übereinstimmung. Wenn eine übereinstimmende allgemeine Regel einen definierten Zeitraum hat, der nicht in den Client-Regeln enthalten ist, wird auch diese allgemeine Regel verwendet
- Für jede übereinstimmende Regel wird der Ratenlimitzähler inkrementiert. Wenn der Zählerwert größer als das Regellimit ist, wird die Anforderung blockiert
Wenn die Anfrage blockiert wird, erhält der Client eine Textantwort wie diese:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
Sie können die Antwort anpassen, indem Sie die Optionen HttpStatusCode
und QuotaExceededMessage
. Wenn Sie Ihre eigene Antwort implementieren möchten, können Sie ClientRateLimitMiddleware.ReturnQuotaExceededResponse
. Der Wert für den Retry-After
Header wird in Sekunden angegeben.
Wenn für die Anforderung die Rate nicht begrenzt wird, wird der in den Übereinstimmungsregeln definierte längste Zeitraum zum Erstellen der X-Rate-Limit-Header verwendet. Diese Header werden in die Antwort eingefügt:
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
Standardmäßig werden blockierte Anforderungen mit Microsoft.Extensions.Logging.ILogger
protokolliert. Wenn Sie Ihre eigene Protokollierung implementieren möchten, können Sie ClientRateLimitMiddleware.LogBlockedRequest
. Der Standard-Logger gibt die folgenden Informationen aus, wenn für eine Anforderung die Rate begrenzt wird:
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.
Aktualisieren Sie die Ratenlimits zur Laufzeit
Beim Start der Anwendung werden die in appsettings.json
definierten Regeln für die appsettings.json
entweder vom MemoryCacheClientPolicyStore
oder vom DistributedCacheClientPolicyStore
in den Cache geladen, je nachdem, welchen Cache-Provider-Typ Sie verwenden. Sie können auf den Clientrichtlinienspeicher in einem Controller zugreifen und die Regeln wie folgt ändern:
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); } }
Auf diese Weise können Sie die Client-Ratenlimits in einer Datenbank speichern und nach jedem Start der App im Cache ablegen.