Szukaj…


Uwagi

AspNetCoreRateLimit to rozwiązanie ASP.NET Core o otwartym kodzie źródłowym, zaprojektowane w celu kontroli liczby żądań klientów do interfejsu API sieci Web lub aplikacji MVC na podstawie adresu IP lub identyfikatora klienta.

Ograniczanie prędkości na podstawie adresu IP klienta

Dzięki oprogramowaniu pośredniczącemu IpRateLimit możesz ustawić wiele limitów dla różnych scenariuszy, np. Zezwalając, aby IP lub zakres adresów IP wykonywał maksymalną liczbę połączeń w odstępach czasowych, takich jak sekunda, 15 minut itp. Możesz zdefiniować te limity, aby odpowiedzieć na wszystkie żądania skierowane do API lub możesz ograniczyć zakres do każdej ścieżki URL lub czasownika i ścieżki HTTP.

Ustawiać

Instalacja NuGet :

Install-Package AspNetCoreRateLimit

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

Oprogramowanie pośrednie należy zarejestrować przed innymi komponentami oprócz loggerFactory.

jeśli załadujesz saldo swojej aplikacji, będziesz musiał użyć IDistributedCache z Redis lub SQLServer, aby wszystkie instancje pustułki miały ten sam magazyn limitów prędkości. Zamiast magazynów w pamięci należy wstrzykiwać rozproszone sklepy w następujący sposób:

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

Konfiguracja i ogólne zasady 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
      }
    ]
  }

Jeśli EnableEndpointRateLimiting ma wartość false wówczas ograniczenia będą obowiązywać globalnie i będą obowiązywać tylko reguły, które mają jako punkt końcowy * . Na przykład, jeśli ustawisz limit 5 połączeń na sekundę, każde połączenie HTTP do dowolnego punktu końcowego będzie wliczane do tego limitu.

Jeśli EnableEndpointRateLimiting ma wartość true wówczas limity będą obowiązywać dla każdego punktu końcowego, jak w {HTTP_Verb}{PATH} . Na przykład, jeśli ustawisz limit 5 połączeń na sekundę dla *:/api/values klient może wywoływać GET /api/values 5 razy na sekundę, ale także 5 razy PUT /api/values .

Jeśli StackBlockedRequests jest ustawiony na false odrzucone wywołania, nie są dodawane do licznika przepustnicy. Jeśli klient wysyła 3 żądania na sekundę i ustawiłeś limit jednego połączenia na sekundę, inne limity, takie jak licznik minut lub dziennie, będą rejestrować tylko pierwsze połączenie, które nie zostało zablokowane. Jeśli chcesz, aby odrzucone żądania były wliczane do innych limitów, musisz ustawić StackBlockedRequests na wartość true .

RealIpHeader służy do wyodrębnienia adresu IP klienta, gdy serwer Kestrel znajduje się za odwrotnym proxy, jeśli twój serwer proxy używa innego nagłówka, wówczas X-Real-IP używa tej opcji, aby go skonfigurować.

ClientIdHeader służy do wyodrębnienia identyfikatora klienta dla białej listy, jeśli identyfikator klienta jest obecny w tym nagłówku i jest zgodny z wartością określoną w ClientWhitelist, wówczas nie są stosowane żadne limity stawek.

Zastąp zasady ogólne dla określonych adresów 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
          }
        ]
      }
    ]
  }

Pole IP obsługuje wartości i zakresy IP v4 i v6, takie jak „192.168.0.0/24”, „fe80 :: / 10” lub „192.168.0.0-192.168.0.255”.

Definiowanie reguł limitów stawek

Reguła składa się z punktu końcowego, okresu i limitu.

Format punktu końcowego to {HTTP_Verb}:{PATH} , możesz kierować na dowolny czasownik HTTP za pomocą symbolu gwiazdki.

Format okresu to {INT}{PERIOD_TYPE} , możesz użyć jednego z następujących typów okresów: s, m, h, d .

Format limitu to {LONG} .

Przykłady :

Ograniczenie prędkości wszystkich punktów końcowych do 2 połączeń na sekundę:

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

Jeśli z tego samego adresu IP w tej samej sekundzie wykonasz 3 połączenia GET z wartościami api / wartości, ostatnie połączenie zostanie zablokowane. Ale jeśli w tej samej sekundzie również wywołasz PUT api / wartości, żądanie zostanie zrealizowane, ponieważ jest to inny punkt końcowy. Gdy ograniczenie prędkości punktu końcowego jest włączone, każde połączenie jest ograniczone w oparciu o {HTTP_Verb}{PATH} .

Ogranicz limit połączeń z dowolnym czasownikiem HTTP na /api/values do 5 połączeń na 15 minut:

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

Limit stawek ODBIERZ połączenie do /api/values do 5 połączeń na godzinę:

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

Jeśli z tego samego adresu IP w ciągu godziny wykonasz 6 wywołań GET do api / wartości, ostatnie połączenie zostanie zablokowane. Ale jeśli w tej samej godzinie również wywołasz GET api / wartości / 1, żądanie zostanie zrealizowane, ponieważ jest to inny punkt końcowy.

Zachowanie

Gdy klient wykonuje połączenie HTTP, IpRateLimitMiddleware wykonuje następujące czynności:

  • wyodrębnia adres IP, identyfikator klienta, czasownik HTTP i adres URL z obiektu żądania, jeśli chcesz wdrożyć własną logikę wyodrębniania, możesz przesłonić IpRateLimitMiddleware.SetIdentity
  • szuka adresu IP, identyfikatora klienta i adresu URL na białej liście, jeśli są zgodne, wówczas nie są podejmowane żadne działania
  • wyszukuje dopasowanie w regułach IP, wszystkie obowiązujące reguły są pogrupowane według okresu, dla każdego okresu stosowana jest najbardziej restrykcyjna reguła
  • wyszukuje dopasowanie w regułach ogólnych, jeśli ogólna reguła, która pasuje, ma zdefiniowany okres, który nie jest obecny w regułach własności intelektualnej, wówczas używana jest również ta reguła ogólna
  • dla każdej pasującej reguły licznik limitu prędkości jest zwiększany, jeśli wartość licznika jest większa niż limit reguły, wówczas żądanie zostaje zablokowane

Jeśli żądanie zostanie zablokowane, klient otrzyma odpowiedź tekstową w następujący sposób:

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

Możesz dostosować odpowiedź, zmieniając te opcje HttpStatusCode i QuotaExceededMessage , jeśli chcesz zaimplementować własną odpowiedź, możesz przesłonić IpRateLimitMiddleware.ReturnQuotaExceededResponse . Wartość nagłówka Retry-After jest wyrażana w sekundach.

Jeśli żądanie nie ma ograniczonej prędkości, wówczas do skomponowania nagłówków X-Rate-Limit wykorzystywany jest najdłuższy okres zdefiniowany w regułach dopasowywania, nagłówki te są wstrzykiwane w odpowiedzi:

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

Domyślnie zablokowane żądanie jest rejestrowane za pomocą Microsoft.Extensions.Logging.ILogger , jeśli chcesz wdrożyć własne rejestrowanie, możesz zastąpić IpRateLimitMiddleware.LogBlockedRequest . Domyślny program rejestrujący emituje następujące informacje, gdy żądanie ma ograniczoną szybkość:

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.

Aktualizuj limity częstości w czasie wykonywania

Podczas uruchamiania aplikacji reguły limitu szybkości IP zdefiniowane w appsettings.json są ładowane do pamięci podręcznej przez MemoryCacheClientPolicyStore lub DistributedCacheIpPolicyStore zależności od używanego dostawcy pamięci podręcznej. Możesz uzyskać dostęp do magazynu zasad IP w kontrolerze i zmodyfikować reguły IP w następujący sposób:

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

W ten sposób możesz przechowywać limity prędkości IP w bazie danych i wypychać je w pamięci podręcznej po każdym uruchomieniu aplikacji.

Ograniczenie stawki na podstawie identyfikatora klienta

Dzięki oprogramowaniu pośredniczącemu ClientRateLimit możesz ustawić wiele limitów dla różnych scenariuszy, np. Zezwalając klientowi na wykonywanie maksymalnej liczby połączeń w interwale czasowym, takim jak sekunda, 15 minut itp. Możesz zdefiniować te limity, aby odpowiedzieć na wszystkie żądania wysłane do API lub może ograniczyć ograniczenia do każdej ścieżki URL lub czasownika i ścieżki HTTP.

Ustawiać

Instalacja NuGet :

Install-Package AspNetCoreRateLimit

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

Oprogramowanie pośrednie należy zarejestrować przed innymi komponentami oprócz loggerFactory.

jeśli załadujesz saldo swojej aplikacji, będziesz musiał użyć IDistributedCache z Redis lub SQLServer, aby wszystkie instancje pustułki miały ten sam magazyn limitów prędkości. Zamiast magazynów w pamięci należy wstrzykiwać rozproszone sklepy w następujący sposób:

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

Konfiguracja i ogólne zasady 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
      }
    ]
  }

Jeśli EnableEndpointRateLimiting ma wartość false wówczas ograniczenia będą obowiązywać globalnie i będą obowiązywać tylko reguły, które mają jako punkt końcowy * . Na przykład, jeśli ustawisz limit 5 połączeń na sekundę, każde połączenie HTTP do dowolnego punktu końcowego będzie wliczane do tego limitu.

Jeśli EnableEndpointRateLimiting ma wartość true wówczas limity będą obowiązywać dla każdego punktu końcowego, jak w {HTTP_Verb}{PATH} . Na przykład, jeśli ustawisz limit 5 połączeń na sekundę dla *:/api/values klient może wywoływać GET /api/values 5 razy na sekundę, ale także 5 razy PUT /api/values .

Jeśli StackBlockedRequests jest ustawiony na false odrzucone wywołania, nie są dodawane do licznika przepustnicy. Jeśli klient wysyła 3 żądania na sekundę i ustawiłeś limit jednego połączenia na sekundę, inne limity, takie jak licznik minut lub dziennie, będą rejestrować tylko pierwsze połączenie, które nie zostało zablokowane. Jeśli chcesz, aby odrzucone żądania były wliczane do innych limitów, musisz ustawić StackBlockedRequests na wartość true .

ClientIdHeader służy do wyodrębnienia identyfikatora klienta, jeśli identyfikator klienta jest obecny w tym nagłówku i jest zgodny z wartością określoną w ClientWhitelist, wówczas nie są stosowane żadne ograniczenia szybkości.

Zastąp zasady ogólne dla określonych klientów 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
          }
        ]
      }
    ]
  }

Definiowanie reguł limitów stawek

Reguła składa się z punktu końcowego, okresu i limitu.

Format punktu końcowego to {HTTP_Verb}:{PATH} , możesz kierować na dowolny czasownik HTTP za pomocą symbolu gwiazdki.

Format okresu to {INT}{PERIOD_TYPE} , możesz użyć jednego z następujących typów okresów: s, m, h, d .

Format limitu to {LONG} .

Przykłady :

Ograniczenie prędkości wszystkich punktów końcowych do 2 połączeń na sekundę:

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

Jeśli w tej samej sekundzie klient wykona 3 wywołania GET do api / wartości, ostatnie połączenie zostanie zablokowane. Ale jeśli w tej samej sekundzie wywoła również PUT api / wartości, żądanie zostanie zrealizowane, ponieważ jest to inny punkt końcowy. Gdy ograniczenie prędkości punktu końcowego jest włączone, każde połączenie jest ograniczone w oparciu o {HTTP_Verb}{PATH} .

Ogranicz limit połączeń z dowolnym czasownikiem HTTP na /api/values do 5 połączeń na 15 minut:

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

Limit stawek ODBIERZ połączenie do /api/values do 5 połączeń na godzinę:

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

Jeśli w ciągu godziny klient wykona 6 wywołań GET do api / wartości, ostatnie połączenie zostanie zablokowane. Ale jeśli w tej samej godzinie również wywoła GET api / values / 1, żądanie zostanie zrealizowane, ponieważ jest to inny punkt końcowy.

Zachowanie

Gdy klient wykonuje połączenie HTTP, ClientRateLimitMiddleware wykonuje następujące czynności:

  • wyodrębnia identyfikator klienta, czasownik HTTP i adres URL z obiektu żądania, jeśli chcesz wdrożyć własną logikę wyodrębniania, możesz zastąpić ClientRateLimitMiddleware.SetIdentity
  • wyszukuje identyfikator klienta i adres URL na białej liście, jeśli są zgodne, wówczas nie są podejmowane żadne działania
  • wyszukuje dopasowanie w regułach klienta, wszystkie obowiązujące reguły są pogrupowane według okresu, dla każdego okresu stosowana jest najbardziej restrykcyjna reguła
  • wyszukuje dopasowanie w regułach ogólnych, jeśli ogólna reguła, która pasuje, ma zdefiniowany okres, którego nie ma w regułach klienta, wówczas używana jest również ta reguła ogólna
  • dla każdej pasującej reguły licznik limitu prędkości jest zwiększany, jeśli wartość licznika jest większa niż limit reguły, wówczas żądanie zostaje zablokowane

Jeśli żądanie zostanie zablokowane, klient otrzyma odpowiedź tekstową w następujący sposób:

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

Możesz dostosować odpowiedź, zmieniając te opcje HttpStatusCode i QuotaExceededMessage , jeśli chcesz zaimplementować własną odpowiedź, możesz przesłonić ClientRateLimitMiddleware.ReturnQuotaExceededResponse . Wartość nagłówka Retry-After jest wyrażana w sekundach.

Jeśli żądanie nie ma ograniczonej prędkości, wówczas do skomponowania nagłówków X-Rate-Limit wykorzystywany jest najdłuższy okres zdefiniowany w regułach dopasowywania, nagłówki te są wstrzykiwane w odpowiedzi:

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

Domyślnie zablokowane żądanie jest rejestrowane za pomocą Microsoft.Extensions.Logging.ILogger , jeśli chcesz wdrożyć własne rejestrowanie, możesz zastąpić ClientRateLimitMiddleware.LogBlockedRequest . Domyślny program rejestrujący emituje następujące informacje, gdy żądanie ma ograniczoną szybkość:

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.

Aktualizuj limity częstości w czasie wykonywania

Podczas uruchamiania aplikacji reguły limitów prędkości klienta zdefiniowane w appsettings.json są ładowane do pamięci podręcznej przez MemoryCacheClientPolicyStore lub DistributedCacheClientPolicyStore zależności od używanego dostawcy pamięci podręcznej. Możesz uzyskać dostęp do magazynu zasad klienta w kontrolerze i zmodyfikować reguły w następujący sposób:

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

W ten sposób możesz przechowywać limity stawek klienta w bazie danych i przesyłać je do pamięci podręcznej po każdym uruchomieniu aplikacji.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow