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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow