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 Sie IpRateLimitMiddleware.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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow