Recherche…


Remarques

AspNetCoreRateLimit est une solution de limitation de débit ASP.NET Core open source conçue pour contrôler le taux de requêtes que les clients peuvent adresser à une API Web ou à une application MVC en fonction de l'adresse IP ou de l'ID client.

Limitation de débit basée sur l'adresse IP du client

Avec le middleware IpRateLimit, vous pouvez définir plusieurs limites pour différents scénarios, comme autoriser une plage IP ou IP à effectuer un nombre maximum d'appels dans un intervalle de temps de 15 minutes, etc. Vous pouvez définir ces limites pour adresser toutes les requêtes API ou vous pouvez définir les limites de chaque chemin d'URL ou verbe et chemin HTTP.

Installer

NuGet installer :

Install-Package AspNetCoreRateLimit

Code Startup.cs :

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();
}

Vous devez enregistrer le middleware avant tout autre composant, à l'exception de loggerFactory.

Si vous chargez votre application, vous devez utiliser IDistributedCache avec Redis ou SQLServer pour que toutes les instances de IDistributedCache aient le même magasin de limites de débit. Au lieu des magasins en mémoire, vous devez injecter les magasins distribués comme ceci:

    // inject counter and rules distributed cache stores
    services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();

Configuration et règles générales 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
      }
    ]
  }

Si EnableEndpointRateLimiting est défini sur false les limites s'appliquent globalement et seules les règles ayant pour point de terminaison * seront appliquées. Par exemple, si vous définissez une limite de 5 appels par seconde, tout appel HTTP à un noeud final sera comptabilisé dans cette limite.

Si EnableEndpointRateLimiting est défini sur true les limites s'appliquent à chaque noeud final, comme dans {HTTP_Verb}{PATH} . Par exemple, si vous définissez une limite de 5 appels par seconde pour *:/api/values un client peut appeler GET /api/values 5 fois par seconde mais également 5 fois PUT /api/values .

Si StackBlockedRequests est défini sur false appels rejetés ne sont pas ajoutés au compteur d'accélération. Si un client effectue 3 requêtes par seconde et que vous définissez une limite d'un appel par seconde, les autres limites, telles que les compteurs par minute ou par jour, enregistrent uniquement le premier appel, celui qui n'a pas été bloqué. Si vous souhaitez que les demandes rejetées soient comptabilisées dans les autres limites, vous devez définir StackBlockedRequests sur true .

RealIpHeader est utilisé pour extraire l'adresse IP du client lorsque votre serveur Kestrel se trouve derrière un proxy inverse. Si votre proxy utilise un en-tête différent, X-Real-IP utilise cette option pour le configurer.

ClientIdHeader est utilisé pour extraire l'ID client pour la liste blanche, si un identifiant client est présent dans cet en-tête et correspond à une valeur spécifiée dans ClientWhitelist, aucune limite de taux n'est appliquée.

Remplacez les règles générales pour des adresses IP spécifiques 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
          }
        ]
      }
    ]
  }

Le champ IP prend en charge les valeurs IP v4 et v6 et se situe entre "192.168.0.0/24", "fe80 :: / 10" ou "192.168.0.0-192.168.0.255".

Définition des règles de limite de taux

Une règle est composée d'un noeud final, d'une période et d'une limite.

Le format du point de terminaison est {HTTP_Verb}:{PATH} , vous pouvez cibler n'importe quel verbe HTTP en utilisant le symbole astérisque.

Le format de période est {INT}{PERIOD_TYPE} , vous pouvez utiliser l'un des types de période suivants: s, m, h, d .

Le format de limite est {LONG} .

Exemples :

Le taux limite tous les points de terminaison à 2 appels par seconde:

{
 "Endpoint": "*",
 "Period": "1s",
 "Limit": 2
}

Si, à partir de la même adresse IP, dans la même seconde, vous effectuerez 3 appels GET vers api / valeurs, le dernier appel sera bloqué. Mais si, dans la même seconde, vous appelez PIT api / values, la requête sera transmise parce que le point de terminaison est différent. Lorsque la limitation de la fréquence d'extrémité est activée, chaque appel est limité par le taux basé sur {HTTP_Verb}{PATH} .

Le taux limite les appels avec n'importe quel verbe HTTP à /api/values à 5 appels par 15 minutes:

{
 "Endpoint": "*:/api/values",
 "Period": "15m",
 "Limit": 5
}

Taux limite GET appel à /api/values à 5 appels par heure:

{
 "Endpoint": "get:/api/values",
 "Period": "1h",
 "Limit": 5
}

Si, à partir de la même adresse IP, vous effectuez 6 appels GET vers api / valeurs, le dernier appel sera bloqué. Mais si, dans la même heure, vous appelez GET api / values ​​/ 1, la requête est transmise parce que le point de terminaison est différent.

Comportement

Lorsqu'un client effectue un appel HTTP, IpRateLimitMiddleware effectue les opérations suivantes:

  • extrait l'adresse IP, l'identifiant du client, le verbe HTTP et l'URL de l'objet de requête, si vous souhaitez implémenter votre propre logique d'extraction, vous pouvez remplacer l' IpRateLimitMiddleware.SetIdentity
  • recherche l'adresse IP, l'identifiant du client et l'URL dans les listes blanches, s'il y a des correspondances, aucune action n'est prise
  • recherche dans les règles IP pour une correspondance, toutes les règles qui s'appliquent sont regroupées par période, pour chaque période la règle la plus restrictive est utilisée
  • recherche dans les règles générales une correspondance, si une règle générale qui correspond à une période définie n'est pas présente dans les règles IP, cette règle générale est également utilisée
  • pour chaque règle de correspondance, le compteur de limite de débit est incrémenté, si la valeur du compteur est supérieure à la limite de la règle, la requête est bloquée

Si la requête est bloquée, le client reçoit une réponse textuelle comme ceci:

Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.

Vous pouvez personnaliser la réponse en modifiant ces options HttpStatusCode et QuotaExceededMessage . Si vous souhaitez implémenter votre propre réponse, vous pouvez remplacer IpRateLimitMiddleware.ReturnQuotaExceededResponse . La valeur de l'en Retry-After tête Retry-After est exprimée en secondes.

Si la demande ne reçoit pas de taux limité, la plus longue période définie dans les règles de correspondance est utilisée pour composer les en-têtes X-Rate-Limit, ces en-têtes sont injectés dans la réponse:

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

Par défaut, les requêtes bloquées sont consignées à l'aide de Microsoft.Extensions.Logging.ILogger . Si vous souhaitez implémenter votre propre journalisation, vous pouvez remplacer IpRateLimitMiddleware.LogBlockedRequest . Le consignateur par défaut émet les informations suivantes lorsqu'une demande reçoit un taux limité:

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.

Mettre à jour les limites de taux lors de l'exécution

Au démarrage de l'application, les règles de limite de débit IP définies dans appsettings.json sont chargées dans le cache par MemoryCacheClientPolicyStore ou DistributedCacheIpPolicyStore selon le type de fournisseur de cache utilisé. Vous pouvez accéder au magasin de règles Ip dans un contrôleur et modifier les règles IP comme suit:

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);
    }
}

De cette façon, vous pouvez stocker les limites de taux IP dans une base de données et les mettre en cache après le démarrage de chaque application.

Limitation du taux basé sur l'ID du client

Avec le middleware ClientRateLimit, vous pouvez définir plusieurs limites pour différents scénarios, comme autoriser un client à effectuer un nombre maximal d'appels par intervalle de temps, par seconde, 15 minutes, etc. Vous pouvez définir ces limites pour adresser toutes les requêtes adressées à une API peut couvrir les limites de chaque chemin d'URL ou de verbe et chemin HTTP.

Installer

NuGet installer :

Install-Package AspNetCoreRateLimit

Code Startup.cs :

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();
}

Vous devez enregistrer le middleware avant tout autre composant, à l'exception de loggerFactory.

Si vous chargez votre application, vous devez utiliser IDistributedCache avec Redis ou SQLServer pour que toutes les instances de IDistributedCache aient le même magasin de limites de débit. Au lieu des magasins en mémoire, vous devez injecter les magasins distribués comme ceci:

    // inject counter and rules distributed cache stores
    services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();

Configuration et règles générales 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
      }
    ]
  }

Si EnableEndpointRateLimiting est défini sur false les limites s'appliquent globalement et seules les règles ayant pour point de terminaison * seront appliquées. Par exemple, si vous définissez une limite de 5 appels par seconde, tout appel HTTP à un noeud final sera comptabilisé dans cette limite.

Si EnableEndpointRateLimiting est défini sur true les limites s'appliquent à chaque noeud final, comme dans {HTTP_Verb}{PATH} . Par exemple, si vous définissez une limite de 5 appels par seconde pour *:/api/values un client peut appeler GET /api/values 5 fois par seconde mais également 5 fois PUT /api/values .

Si StackBlockedRequests est défini sur false appels rejetés ne sont pas ajoutés au compteur d'accélération. Si un client effectue 3 requêtes par seconde et que vous définissez une limite d'un appel par seconde, les autres limites, telles que les compteurs par minute ou par jour, enregistrent uniquement le premier appel, celui qui n'a pas été bloqué. Si vous souhaitez que les demandes rejetées soient comptabilisées dans les autres limites, vous devez définir StackBlockedRequests sur true .

ClientIdHeader est utilisé pour extraire l'ID du client, si un identifiant de client est présent dans cet en-tête et correspond à une valeur spécifiée dans ClientWhitelist, aucune limite de taux n'est appliquée.

Remplacez les règles générales pour des clients spécifiques 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
          }
        ]
      }
    ]
  }

Définition des règles de limite de taux

Une règle est composée d'un noeud final, d'une période et d'une limite.

Le format du point de terminaison est {HTTP_Verb}:{PATH} , vous pouvez cibler n'importe quel verbe HTTP en utilisant le symbole astérisque.

Le format de période est {INT}{PERIOD_TYPE} , vous pouvez utiliser l'un des types de période suivants: s, m, h, d .

Le format de limite est {LONG} .

Exemples :

Le taux limite tous les points de terminaison à 2 appels par seconde:

{
 "Endpoint": "*",
 "Period": "1s",
 "Limit": 2
}

Si, dans la même seconde, un client effectue 3 appels GET vers api / valeurs, le dernier appel sera bloqué. Mais si, dans la même seconde, il appelle PIT api / values, la requête passera par un point final différent. Lorsque la limitation de la fréquence d'extrémité est activée, chaque appel est limité par le taux basé sur {HTTP_Verb}{PATH} .

Le taux limite les appels avec n'importe quel verbe HTTP à /api/values à 5 appels par 15 minutes:

{
 "Endpoint": "*:/api/values",
 "Period": "15m",
 "Limit": 5
}

Taux limite GET appel à /api/values à 5 appels par heure:

{
 "Endpoint": "get:/api/values",
 "Period": "1h",
 "Limit": 5
}

Si dans une heure, un client effectue 6 appels GET vers api / valeurs, le dernier appel sera bloqué. Mais si dans la même heure il appelle GET api / values ​​/ 1 aussi, la requête passera parce que c'est un point final différent.

Comportement

Lorsqu'un client effectue un appel HTTP, ClientRateLimitMiddleware effectue les opérations suivantes:

  • extrait l'ID du client, le verbe HTTP et l'URL de l'objet de requête, si vous souhaitez implémenter votre propre logique d'extraction, vous pouvez remplacer ClientRateLimitMiddleware.SetIdentity
  • recherche l'identifiant et l'URL du client dans les listes blanches, s'il y a des correspondances, aucune action n'est prise
  • recherche dans le client les règles d'une correspondance, toutes les règles qui s'appliquent sont regroupées par période, pour chaque période la règle la plus restrictive est utilisée
  • recherche dans les règles générales une correspondance, si une règle générale qui correspond à une période définie est absente des règles du client, cette règle générale est également utilisée
  • pour chaque règle de correspondance, le compteur de limite de débit est incrémenté, si la valeur du compteur est supérieure à la limite de la règle, la requête est bloquée

Si la requête est bloquée, le client reçoit une réponse textuelle comme ceci:

Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.

Vous pouvez personnaliser la réponse en modifiant ces options HttpStatusCode et QuotaExceededMessage . Si vous souhaitez implémenter votre propre réponse, vous pouvez remplacer ClientRateLimitMiddleware.ReturnQuotaExceededResponse . La valeur de l'en Retry-After tête Retry-After est exprimée en secondes.

Si la demande ne reçoit pas de taux limité, la plus longue période définie dans les règles de correspondance est utilisée pour composer les en-têtes X-Rate-Limit, ces en-têtes sont injectés dans la réponse:

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

Par défaut, les requêtes bloquées sont consignées à l'aide de Microsoft.Extensions.Logging.ILogger . Si vous souhaitez implémenter votre propre journalisation, vous pouvez remplacer ClientRateLimitMiddleware.LogBlockedRequest . Le consignateur par défaut émet les informations suivantes lorsqu'une demande reçoit un taux limité:

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.

Mettre à jour les limites de taux lors de l'exécution

Au démarrage de l'application, les règles de limite de débit du client définies dans appsettings.json sont chargées dans le cache par MemoryCacheClientPolicyStore ou DistributedCacheClientPolicyStore selon le type de fournisseur de cache utilisé. Vous pouvez accéder au magasin de règles client dans un contrôleur et modifier les règles comme suit:

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);
    }
}

De cette façon, vous pouvez stocker les limites de taux client dans une base de données et les mettre en cache après le démarrage de chaque application.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow