Megosztás a következőn keresztül:


Köztes szoftver sebességkorlátozása a ASP.NET Core-ban

Arvin Kahbazi, Maarten Balliauwés Rick Anderson

A Microsoft.AspNetCore.RateLimiting köztes szoftver sebességkorlátozó köztes szoftvereket biztosít. Az alkalmazások konfigurálják a sebességkorlátozó szabályzatokat, majd csatolják a szabályzatokat a végpontokhoz. A sebességkorlátozást használó alkalmazásokat az üzembe helyezés előtt gondosan be kell tölteni és felül kell vizsgálni. További információt a jelen cikkben A sebességkorlátozó végpontok tesztelése című cikkben talál.

Az aránykorlátozásról az közbenső szoftvercímű részben olvashat.

Miért érdemes sebességkorlátozást használni?

A sebességkorlátozás használható a bejövő kérések alkalmazásba irányuló folyamatának kezelésére. A sebességkorlátozás megvalósításának fő okai:

  • Visszaélések megakadályozása: A sebességkorlátozás segít megvédeni az alkalmazásokat a visszaélésektől azáltal, hogy korlátozza a felhasználó vagy ügyfél által egy adott időszakban küldött kérelmek számát. Ez különösen fontos a nyilvános API-k esetében.
  • Méltányos használat biztosítása: A korlátok beállításával minden felhasználó tisztességes hozzáféréssel rendelkezik az erőforrásokhoz, megakadályozva a felhasználók számára a rendszer monopolizálását.
  • Erőforrások védelme: A sebességkorlátozás segít megelőzni a kiszolgáló túlterhelését a feldolgozható kérések számának szabályozásával, így védve a háttérerőforrások túlterhelését.
  • Biztonságijavítása: A szolgáltatásmegtagadási (DoS-) támadások kockázatát csökkentheti a kérések feldolgozásának sebességének korlátozásával, ami megnehezíti a támadók számára a rendszer elárasztását.
  • Jobb teljesítmény: A bejövő kérések sebességének szabályozásával az alkalmazás optimális teljesítménye és válaszképessége fenntartható, így jobb felhasználói élmény érhető el.
  • Cost Management: A használaton alapuló költségekkel járó szolgáltatások esetében a sebességkorlátozás segíthet a költségek kezelésében és előrejelzésében a feldolgozott kérelmek mennyiségének szabályozásával.

A sebességkorlátozás implementálása egy ASP.NET Core-alkalmazásban segíthet fenntartani a stabilitást, a biztonságot és a teljesítményt, biztosítva a megbízható és hatékony szolgáltatást minden felhasználó számára.

DDoS-támadások megakadályozása

Bár a sebességkorlátozás segíthet csökkenteni a szolgáltatásmegtagadási (DoS-) támadások kockázatát a kérelmek feldolgozásának sebességének korlátozásával, ez nem átfogó megoldás az elosztott szolgáltatásmegtagadási (DDoS-) támadásokra. A DDoS-támadások során több rendszer is túlterheli az alkalmazásokat a kérések áradatával, ami megnehezíti a sebességkorlátozás egyedüli kezelését.

A robusztus DDoS-védelem érdekében fontolja meg egy kereskedelmi DDoS védelmi szolgáltatás használatát. Ezek a szolgáltatások olyan speciális funkciókat kínálnak, mint például:

  • forgalomelemzési: A bejövő forgalom folyamatos monitorozása és elemzése a DDoS-támadások valós idejű észleléséhez és enyhítéséhez.
  • méretezhetőségi: A nagy méretű támadások kezelése több kiszolgáló és adatközpont közötti forgalom elosztásával.
  • automatikus kockázatcsökkentési: Automatizált válaszmechanizmusok a rosszindulatú forgalom manuális beavatkozás nélküli gyors blokkolásához.
  • globális hálózati: A kiszolgálók globális hálózata, amely a forráshoz közelebbi támadásokat képes elnyelni és enyhíteni.
  • Állandó frissítések: A kereskedelmi szolgáltatások folyamatosan nyomon követik és frissítik védelmi mechanizmusaikat, hogy alkalmazkodjanak az új és változó fenyegetésekhez.

Felhőalapú üzemeltetési szolgáltatás használatakor a DDoS-védelem általában az üzemeltetési megoldás részeként érhető el, például Azure Web Application Firewall, AWS Shield vagy Google Cloud Armor. A dedikált védelem webalkalmazási tűzfalként (WAF) vagy CDN-megoldás részeként érhető el, például Cloudflare vagy Akamai Kona Site Defender

A kereskedelmi DDoS védelmi szolgáltatás és a sebességkorlátozás együttes megvalósítása átfogó védelmi stratégiát biztosíthat, biztosítva az alkalmazások stabilitását, biztonságát és teljesítményét.

Sebességkorlátozó köztes szoftver használata

Az alábbi lépések bemutatják, hogyan használható a sebességkorlátozó köztes szoftver egy ASP.NET Core-alkalmazásban:

  1. Sebességkorlátozó szolgáltatások konfigurálása.

A Program.cs fájlban konfigurálja a sebességkorlátozó szolgáltatásokat a megfelelő sebességkorlátozó szabályzatok hozzáadásával. A szabályzatok globális vagy elnevezett szabályzatként is definiálhatók. Az alábbi példa 10 kérést engedélyez percenként felhasználónként (identitásonként) vagy globálisan:

builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(),
            factory: partition => new FixedWindowRateLimiterOptions
            {
                AutoReplenishment = true,
                PermitLimit = 10,
                QueueLimit = 0,
                Window = TimeSpan.FromMinutes(1)
            }));
});

Az elnevezett szabályzatokat explicit módon kell alkalmazni az oldalakra vagy végpontokra. Az alábbi példa egy "fixed" nevű rögzített ablakkorlátozó-szabályzatot ad hozzá, amelyet később hozzáadunk egy végponthoz:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("fixed", opt =>
    {
        opt.PermitLimit = 4;
        opt.Window = TimeSpan.FromSeconds(12);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 2;
    });
});

var app = builder.Build();

A globális korlátozó automatikusan vonatkozik az összes végpontra, ha beállításokon keresztül van konfigurálva. GlobalLimiter.

  1. Köztes szoftver sebességkorlátozásának engedélyezése

    A Program.cs fájlban engedélyezze a köztes szoftver sebességkorlátozását UseRateLimitermeghívásával:

app.UseRouting();

app.UseRateLimiter();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

Sebességkorlátozó szabályzatok alkalmazása végpontokra vagy lapokra

Sebességkorlátozás alkalmazása a WebAPI-végpontokra

Névvel ellátott szabályzat alkalmazása a végpontra vagy csoportra, például:


app.MapGet("/api/resource", () => "This endpoint is rate limited")
   .RequireRateLimiting("fixed"); // Apply specific policy to an endpoint

Sebességkorlátozás alkalmazása MVC-vezérlőkre

Alkalmazza a konfigurált sebességkorlátozó szabályzatokat adott végpontokra vagy globálisan. Például a "rögzített" szabályzat alkalmazása az összes vezérlővégpontra:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireRateLimiting("fixed");
});

Sebességkorlátozás alkalmazása kiszolgálóoldali Blazor-alkalmazásokra

Az alkalmazás összes útválasztható Razor összetevőjére vonatkozó forgalomkorlátozás beállításához adja meg a RequireRateLimiting-et a MapRazorComponents hívás során, a Program fájlban található forgalomkorlátozó házirend nevével. Az alábbi példában a "policy" nevű sebességkorlátozó szabályzat lesz alkalmazva:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .RequireRateLimiting("policy");

Ahhoz, hogy egy Razor fájlon keresztül házirendet állítson be egyetlen routable _Imports.razor összetevőhöz vagy egy összetevőmappához, a házirend nevével a [EnableRateLimiting] attribútumot alkalmazza. Az alábbi példában a "override" nevű sebességkorlátozó szabályzat lesz alkalmazva. A szabályzat lecseréli a végpontra jelenleg alkalmazott szabályzatokat. A globális korlátozó továbbra is a végponton fut ezzel az attribútummal.

@page "/counter"
@using Microsoft.AspNetCore.RateLimiting
@attribute [EnableRateLimiting("override")]

<h1>Counter</h1>

A [EnableRateLimiting] attribútumot csak akkor alkalmazza a rendszer egy irányítható komponensre vagy komponensek mappájára, illetve egy _Imports.razor fájlon keresztül, ha RequireRateLimitingnincs meghívva MapRazorComponents.

A [DisableRateLimiting] attribútum egy _Imports.razor fájlon keresztül letiltja a sebességkorlátozást egy nem módosítható összetevőre vagy összetevőmappára vonatkozóan.

Sebességkorlátozó algoritmusok

A RateLimiterOptionsExtensions osztály a következő bővítménymetelyeket biztosítja a sebességkorlátozáshoz:

A rögzített, a csúsztatási és a token-korlátozók mindegyike korlátozza a kérelmek maximális számát egy adott időszakban. Az egyidejűségkorlátozó csak az egyidejű kérések számát korlátozza, és nem korlátozza a kérelmek számát egy adott időszakban. A végpont költségét figyelembe kell venni a korlátozó kiválasztásakor. A végpont költsége magában foglalja a felhasznált erőforrásokat, például az időt, az adathozzáférést, a CPU-t és az I/O-t.

Rögzített ablakkorlátozó

A AddFixedWindowLimiter metódus rögzített időkeretet használ a kérelmek korlátozásához. Amikor az időkeret lejár, egy új időkeret kezdődik és a kérelemkorlát alaphelyzetbe kerül.

Vegye figyelembe a következő kódot:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(_ => _
    .AddFixedWindowLimiter(policyName: "fixed", options =>
    {
        options.PermitLimit = 4;
        options.Window = TimeSpan.FromSeconds(12);
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = 2;
    }));

var app = builder.Build();

app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", () => Results.Ok($"Hello {GetTicks()}"))
                           .RequireRateLimiting("fixed");

app.Run();

Az előző kód:

  • Meghívja AddRateLimiter, hogy adjon hozzá egy sebességkorlátozó szolgáltatást a szolgáltatásgyűjteményhez.
  • Meghívja a(z) AddFixedWindowLimiter-t, hogy hozzon létre egy rögzített ablakkorlátozót a(z) "fixed" házirend nevével, és beállítja a paramétereket:
  • PermitLimit 4-hez, az idő pedig Window 12-hez. Minden 12 másodperces ablakban legfeljebb 4 kérés engedélyezett.
  • QueueProcessingOrder és OldestFirst.
  • QueueLimit 2 értékre (állítsa ezt 0 értékre az üzenetsor-kezelési mechanizmus letiltásához).
  • A UseRateLimiter függvény meghívása a sebességkorlátok engedélyezéséhez.

Az alkalmazásoknak konfigurációs kell használniuk a korlátozó beállítások megadásához. Az alábbi kód a konfigurációhoz MyRateLimitOptions használatával frissíti az előző kódot:

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MyRateLimitOptions>(
    builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit));

var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var fixedPolicy = "fixed";

builder.Services.AddRateLimiter(_ => _
    .AddFixedWindowLimiter(policyName: fixedPolicy, options =>
    {
        options.PermitLimit = myOptions.PermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var app = builder.Build();

app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", () => Results.Ok($"Fixed Window Limiter {GetTicks()}"))
                           .RequireRateLimiting(fixedPolicy);

app.Run();

UseRateLimiter UseRouting után kell meghívni a végpontspecifikus API-k sebességkorlátozása esetén. Ha például a [EnableRateLimiting] attribútumot használja, UseRateLimiterUseRoutingután kell meghívni. Ha csak globális korlátokat hív meg, UseRateLimiter hívható meg UseRoutingelőtt.

Tolóablakkorlátozó

Egy csúszóablak-algoritmus:

  • Hasonló a rögzített ablakkorlátozóhoz, de ablakonként szegmenseket ad hozzá. Az ablak minden szegmensintervallumban egy szegmenst csúsztat. A szegmens időköze (ablakidő)/(szegmensek ablakonként).
  • A kérések számának korlátozása egy ablak esetében permitLimit kérésre.
  • Minden időablak n szegmensekre van osztva ablakonként.
  • A lejárt időszegmensből egy ablakkal visszább lévő kérelmek (n az aktuális szegmens előtti szegmensből) hozzáadódnak az aktuális szegmenshez. A leginkább lejárt időszakaszt, amely egy ablakkal korábbra esik, egyszerűen lejárt szegmensnek nevezzük.

Tekintse meg az alábbi táblázatot, amely egy 30 másodperces ablakkal rendelkező tolóablakkorlátozót, ablakonként három szegmenst és 100 kérelemkorlátot tartalmaz:

  • A felső sor és az első oszlop az időszegmenst jeleníti meg.
  • A második sor a fennmaradó elérhető kéréseket jeleníti meg. A fennmaradó kérelmeket a rendszer úgy számítja ki, hogy a rendelkezésre álló kérelmek mínusz a feldolgozott kérelmek és az újrafeldolgozott kérelmek.
  • A kérések mindig az átlós kék vonal mentén mozognak.
  • A 30. időponttól kezdve a lejárt időszakaszból származó kérés visszakerül a kérelemkorlátba, ahogy az a piros sorokban is látható.

kérelmeket, korlátokat és újrafeldolgozott pontokat bemutató táblázat

Az alábbi táblázat az előző gráf adatait mutatja be eltérő formátumban. Az Elérhető oszlop az előző szegmensből elérhető kéréseket jeleníti meg (az előző sorból származó átvitele). Az első sor 100 elérhető kérést jelenít meg, mert nincs korábbi szegmens.

Idő Beszerezhető Elfoglalt Lejárt anyagokból újrahasznosítva Áthozatal
0 100 20 0 80
10 80 30 0 50
20 50 40 0 10
30 10 30 20 0
40 0 10 30 20
50 20 10 40 50
60 50 35 30 45

A következő kód a tolóablak sebességkorlátozóját használja:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);

var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var slidingPolicy = "sliding";

builder.Services.AddRateLimiter(_ => _
    .AddSlidingWindowLimiter(policyName: slidingPolicy, options =>
    {
        options.PermitLimit = myOptions.PermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.SegmentsPerWindow = myOptions.SegmentsPerWindow;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var app = builder.Build();

app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", () => Results.Ok($"Sliding Window Limiter {GetTicks()}"))
                           .RequireRateLimiting(slidingPolicy);

app.Run();

Token vödrös korlátozó

A token vödör korlátozó hasonló a csúszóablak korlátozóhoz, de ahelyett, hogy a lejárt szegmensből származó kapcsolatokat visszaadná, minden feltöltési időszakban rögzített számú tokent ad hozzá. Az egyes szegmensekhez hozzáadott tokenek nem növelhetik a rendelkezésre álló tokenek számát a token vödör határa fölé. Az alábbi táblázat egy 100 tokent és egy 10 másodperces utántöltési periódust tartalmazó korlátozót mutatja be.

Idő Beszerezhető Elfoglalt Hozzáadott Áthozatal
0 100 20 0 80
10 80 10 20 90
20 90 5 15 100
30 100 30 20 90
40 90 6 16 100
50 100 40 20 80
60 80 50 20 50

A következő kód a token vödör korlátozót használja:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);

var tokenPolicy = "token";
var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);

builder.Services.AddRateLimiter(_ => _
    .AddTokenBucketLimiter(policyName: tokenPolicy, options =>
    {
        options.TokenLimit = myOptions.TokenLimit;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
        options.ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.ReplenishmentPeriod);
        options.TokensPerPeriod = myOptions.TokensPerPeriod;
        options.AutoReplenishment = myOptions.AutoReplenishment;
    }));

var app = builder.Build();

app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", () => Results.Ok($"Token Limiter {GetTicks()}"))
                           .RequireRateLimiting(tokenPolicy);

app.Run();

Ha AutoReplenishmenttrueértékre van állítva, a belső időzítő minden ReplenishmentPeriodfeltölti a jogkivonatokat; ha falseértékre van állítva, az alkalmazásnak meg kell hívnia a korláton TryReplenish.

Párhuzamosság korlátozó

Az egyidejűségkorlátozó korlátozza az egyidejű kérések számát. Minden kérelem egy-egy kérelemmel csökkenti az egyidejűségi korlátot. Amikor egy kérés befejeződik, a korlát eggyel nő. A többi kérelemkorlátozóval ellentétben, amelyek egy adott időszakra korlátozzák a kérelmek teljes számát, az egyidejűségkorlátozó csak az egyidejű kérelmek számát korlátozza, és nem korlátozza az adott időszakban a kérelmek számát.

Az alábbi kód az egyidejűségkorlátozót használja:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);

var concurrencyPolicy = "Concurrency";
var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);

builder.Services.AddRateLimiter(_ => _
    .AddConcurrencyLimiter(policyName: concurrencyPolicy, options =>
    {
        options.PermitLimit = myOptions.PermitLimit;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var app = builder.Build();

app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", async () =>
{
    await Task.Delay(500);
    return Results.Ok($"Concurrency Limiter {GetTicks()}");
                              
}).RequireRateLimiting(concurrencyPolicy);

app.Run();

Partíciók adatáramlási korlátozása

Az áramlásszabályozó partíciók külön "vödrökre" osztják a forgalmat, amelyek mindegyike saját áramlás-korlát számlálókat kap. Ez részletesebb vezérlést tesz lehetővé, mint egyetlen globális számláló. A partíció "szegmenseit" különböző kulcsok (például felhasználói azonosító, IP-cím vagy API-kulcs) határozzák meg.

A particionálás előnyei

  • Méltányosság: Egy felhasználó nem használhatja fel a teljes díjkorlátot mindenki számára
  • Granularitás: Különböző korlátok különböző felhasználók/erőforrások részére
  • biztonsági: Hatékonyabb védelem a célzott visszaélések ellen
  • rétegzett szolgáltatási: Különböző korlátokkal rendelkező szolgáltatási szintek támogatása

A particionált sebességkorlátozással részletesen szabályozhatja az API-forgalom kezelésének módját, miközben tisztességes erőforrás-kiosztást biztosít.

IP-cím szerint

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
    RateLimitPartition.GetFixedWindowLimiter(
        partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
        factory: _ => new FixedWindowRateLimiterOptions
        {
            PermitLimit = 50,
            Window = TimeSpan.FromMinutes(1)
        }));

Felhasználó Identity szerint

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
    RateLimitPartition.GetFixedWindowLimiter(
        partitionKey: httpContext.User.Identity?.Name ?? "anonymous",
        factory: _ => new FixedWindowRateLimiterOptions
        {
            PermitLimit = 100,
            Window = TimeSpan.FromMinutes(1)
        }));

API-kulcs szerint

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
    string apiKey = httpContext.Request.Headers["X-API-Key"].ToString() ?? "no-key";

    // Different limits based on key tier
    return apiKey switch
    {
        "premium-key" => RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: apiKey,
            factory: _ => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 1000,
                Window = TimeSpan.FromMinutes(1)
            }),

        _ => RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: apiKey,
            factory: _ => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 100,
                Window = TimeSpan.FromMinutes(1)
            }),
    };
});

Végpont elérési útja szerint

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
    string path = httpContext.Request.Path.ToString();

    // Different limits for different paths
    if (path.StartsWith("/api/public"))
    {
        return RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: $"{httpContext.Connection.RemoteIpAddress}-public",
            factory: _ => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 30,
                Window = TimeSpan.FromSeconds(10)
            });
    }

    return RateLimitPartition.GetFixedWindowLimiter(
        partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
        factory: _ => new FixedWindowRateLimiterOptions
        {
            PermitLimit = 100,
            Window = TimeSpan.FromMinutes(1)
        });
});

Láncolt korlátozók létrehozása

A CreateChained API több PartitionedRateLimiter átadását teszi lehetővé, amelyek egyetlen PartitionedRateLimiter-be kombinálva vannak. A kombinált korlátozó sorrendben futtatja az összes bemeneti korlátot.

A következő kód CreateChainedhasznál:

using System.Globalization;
using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(_ =>
{
    _.OnRejected = async (context, cancellationToken) =>
    {
        if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
        {
            context.HttpContext.Response.Headers.RetryAfter =
                ((int) retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
        }

        context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
        await context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.", cancellationToken);
    };
    _.GlobalLimiter = PartitionedRateLimiter.CreateChained(
        PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        {
            var userAgent = httpContext.Request.Headers.UserAgent.ToString();

            return RateLimitPartition.GetFixedWindowLimiter
            (userAgent, _ =>
                new FixedWindowRateLimiterOptions
                {
                    AutoReplenishment = true,
                    PermitLimit = 4,
                    Window = TimeSpan.FromSeconds(2)
                });
        }),
        PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        {
            var userAgent = httpContext.Request.Headers.UserAgent.ToString();
            
            return RateLimitPartition.GetFixedWindowLimiter
            (userAgent, _ =>
                new FixedWindowRateLimiterOptions
                {
                    AutoReplenishment = true,
                    PermitLimit = 20,    
                    Window = TimeSpan.FromSeconds(30)
                });
        }));
});

var app = builder.Build();
app.UseRateLimiter();

static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");

app.MapGet("/", () => Results.Ok($"Hello {GetTicks()}"));

app.Run();

További információ: CreateChained forráskód

Annak kiválasztása, hogy mi történik, ha egy kérelem sebességkorlátos

Egyszerű esetekben egyszerűen beállíthatja az állapotkódot:

builder.Services.AddRateLimiter(options =>
{
    // Set a custom status code for rejections
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;

    // Rate limiter configuration...
});

A leggyakoribb módszer egy OnRejected visszahívás regisztrálása a sebességkorlátozás konfigurálásakor:

builder.Services.AddRateLimiter(options =>
{
    // Rate limiter configuration...

    options.OnRejected = async (context, cancellationToken) =>
    {
        // Custom rejection handling logic
        context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
        context.HttpContext.Response.Headers["Retry-After"] = "60";

        await context.HttpContext.Response.WriteAsync("Rate limit exceeded. Please try again later.", cancellationToken);

        // Optional logging
        logger.LogWarning("Rate limit exceeded for IP: {IpAddress}",
            context.HttpContext.Connection.RemoteIpAddress);
    };
});

Egy másik lehetőség a kérés várólistára helyezése:

Kérelemsor-kezelés

Ha a sorba állítás engedélyezve van, amikor egy kérés túllépi a sebességkorlátot, egy üzenetsorba kerül, ahol a kérés megvárja, amíg egy engedély elérhetővé válik, vagy amíg időtúllépés nem történik. A kérelmek feldolgozása konfigurálható üzenetsor-sorrend szerint történik.

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api", options =>
    {
        options.PermitLimit = 10;           // Allow 10 requests
        options.Window = TimeSpan.FromSeconds(10);  // Per 10-second window
        options.QueueLimit = 5;             // Queue up to 5 additional requests
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst; // Process oldest requests first
        options.AutoReplenishment = true; // Default: automatically replenish permits
    });
});

EnableRateLimiting és DisableRateLimiting attribútumok

A [EnableRateLimiting] és [DisableRateLimiting] attribútumok alkalmazhatók vezérlőre, műveletmetódusra vagy Razor oldalra. Razor Lapok esetében az attribútumot a Razor lapra kell alkalmazni, nem pedig az oldalkezelőkre. A [EnableRateLimiting] például nem alkalmazható OnGet, OnPostvagy más lapkezelőre.

A [DisableRateLimiting] attribútum letiltja sebességkorlátozást a vezérlőre, a műveleti módszerre vagy a Razor oldalra, függetlenül az elnevezett sebességkorlátozóktól vagy az alkalmazott globális korlátoktól. Vegyük például az alábbi kódot, amely meghívja RequireRateLimiting, hogy alkalmazza a fixedPolicy sebességkorlátozást az összes vezérlővégpontra:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.Configure<MyRateLimitOptions>(
    builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit));

var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var fixedPolicy = "fixed";

builder.Services.AddRateLimiter(_ => _
    .AddFixedWindowLimiter(policyName: fixedPolicy, options =>
    {
        options.PermitLimit = myOptions.PermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var slidingPolicy = "sliding";

builder.Services.AddRateLimiter(_ => _
    .AddSlidingWindowLimiter(policyName: slidingPolicy, options =>
    {
        options.PermitLimit = myOptions.SlidingPermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.SegmentsPerWindow = myOptions.SegmentsPerWindow;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var app = builder.Build();
app.UseRateLimiter();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.MapRazorPages().RequireRateLimiting(slidingPolicy);
app.MapDefaultControllerRoute().RequireRateLimiting(fixedPolicy);

app.Run();

Az alábbi kódban a [DisableRateLimiting] letiltja az áramláshatárolást, és felülbírálja a [EnableRateLimiting("fixed")]-ben meghívott Home2Controller és app.MapDefaultControllerRoute().RequireRateLimiting(fixedPolicy) alkalmazott Program.cs-et.

[EnableRateLimiting("fixed")]
public class Home2Controller : Controller
{
    private readonly ILogger<Home2Controller> _logger;

    public Home2Controller(ILogger<Home2Controller> logger)
    {
        _logger = logger;
    }

    public ActionResult Index()
    {
        return View();
    }

    [EnableRateLimiting("sliding")]
    public ActionResult Privacy()
    {
        return View();
    }

    [DisableRateLimiting]
    public ActionResult NoLimit()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

Az előző kódban a [EnableRateLimiting("sliding")]nincs alkalmazva a Privacy műveleti metódusra, mert Program.csapp.MapDefaultControllerRoute().RequireRateLimiting(fixedPolicy).

Fontolja meg a következő kódot, amely nem hívja meg a RequireRateLimiting-át a MapRazorPages-en vagy a MapDefaultControllerRoute-n:

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.Configure<MyRateLimitOptions>(
    builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit));

var myOptions = new MyRateLimitOptions();
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var fixedPolicy = "fixed";

builder.Services.AddRateLimiter(_ => _
    .AddFixedWindowLimiter(policyName: fixedPolicy, options =>
    {
        options.PermitLimit = myOptions.PermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var slidingPolicy = "sliding";

builder.Services.AddRateLimiter(_ => _
    .AddSlidingWindowLimiter(policyName: slidingPolicy, options =>
    {
        options.PermitLimit = myOptions.SlidingPermitLimit;
        options.Window = TimeSpan.FromSeconds(myOptions.Window);
        options.SegmentsPerWindow = myOptions.SegmentsPerWindow;
        options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        options.QueueLimit = myOptions.QueueLimit;
    }));

var app = builder.Build();

app.UseRateLimiter();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.MapRazorPages();
app.MapDefaultControllerRoute();  // RequireRateLimiting not called

app.Run();

Vegye figyelembe a következő vezérlőt:

[EnableRateLimiting("fixed")]
public class Home2Controller : Controller
{
    private readonly ILogger<Home2Controller> _logger;

    public Home2Controller(ILogger<Home2Controller> logger)
    {
        _logger = logger;
    }

    public ActionResult Index()
    {
        return View();
    }

    [EnableRateLimiting("sliding")]
    public ActionResult Privacy()
    {
        return View();
    }

    [DisableRateLimiting]
    public ActionResult NoLimit()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

Az előző vezérlőben:

  • A "fixed" szabályzat sebességkorlátozóját minden olyan műveletmetelyre alkalmazza a rendszer, amely nem rendelkezik EnableRateLimiting és DisableRateLimiting attribútumokkal.
  • A "sliding" szabályzat sebességkorlátozóját alkalmazza a rendszer a Privacy műveletre.
  • A sebességkorlátozás le van tiltva a NoLimit műveletmetódusban.

Sebességkorlátozó metrikák

A sebességkorlátozó köztes szoftver beépített metrikákat és monitorozási képességeket biztosít annak megértéséhez, hogy a sebességkorlátozások milyen hatással vannak az alkalmazások teljesítményére és a felhasználói élményre. A metrikák listáját lásd a Microsoft.AspNetCore.RateLimiting.

Végpontok tesztelése sebességkorlátozással

Mielőtt üzembe helyezi egy alkalmazást sebességkorlátozás használatával az éles környezetben, végezzen terhelési tesztelést az alkalmazáson a sebességkorlátozók és a használt lehetőségek érvényesítéséhez. Hozzon létre például egy JMeter-szkriptet egy olyan eszközzel, mint BlazeMeter vagy Apache JMeter HTTP(S) tesztszkriptrögzítő, és töltse be a szkriptet az Azure Load Testing.

A felhasználói bemenettel rendelkező partíciók létrehozása sebezhetővé teszi az alkalmazást Szolgáltatásmegtagadási (DoS) támadásokkal szemben. Például az ügyfél IP-címeinek partícióinak létrehozása sebezhetővé teszi az alkalmazást az IP-forráscím-hamisítást alkalmazó szolgáltatásmegtagadási támadásokkal szemben. További információért lásd: BCP 38 RFC 2827 Hálózati bejövő forgalom szűrése: IP forráscím hamisításával végrehajtott szolgáltatásmegtagadási támadások kivédése.

További erőforrások