Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Arvin Kahbazi, Maarten Balliauw a Rick Anderson
Middleware Microsoft.AspNetCore.RateLimiting poskytuje omezování rychlosti. Aplikace konfigurují zásady omezování rychlosti a pak zásady připojují ke koncovým bodům. Aplikace využívající omezování rychlosti by se měly před nasazením pečlivě testovat a kontrolovat. Další informace najdete v části Testování koncových bodů s omezováním rychlosti v tomto článku.
Úvod do omezování rychlosti najdete v tématu Omezování rychlosti middleware.
Proč používat omezování rychlosti
Omezení rychlosti se dá použít ke správě toku příchozích požadavků do aplikace. Klíčové důvody implementace omezování rychlosti:
- Zabránění zneužití: Omezování rychlosti pomáhá chránit aplikaci před zneužitím omezením počtu žádostí, které může uživatel nebo klient provést v daném časovém období. To je zvlášť důležité pro veřejná rozhraní API.
- zajištění spravedlivého využití: Nastavením omezení mají všichni uživatelé spravedlivý přístup k prostředkům, což uživatelům brání v monopolizaci systému.
- Ochrana prostředků: Omezování rychlosti pomáhá zabránit přetížení serveru tím, že řídí počet žádostí, které je možné zpracovat, a tím chrání back-endové prostředky před zahlcením.
- Posílení zabezpečení: Může zmírnit riziko útoků DoS tím, že omezuje rychlost zpracování požadavků, čímž útočníkům znesnadňuje zahltit systém.
- zlepšení výkonu: Díky řízení rychlosti příchozích požadavků je možné udržovat optimální výkon a rychlost odezvy aplikace a zajistit tak lepší uživatelské prostředí.
- Cost Management: U služeb, které účtují náklady na základě využití, může omezení rychlosti pomoci spravovat a předpovídat výdaje kontrolou objemu zpracovávaných požadavků.
Implementace omezování rychlosti v aplikaci ASP.NET Core pomáhá udržovat stabilitu, zabezpečení a výkon a zajistit tak spolehlivou a efektivní službu pro všechny uživatele.
Prevence útoků DDoS
I když omezování rychlosti může pomoct zmírnit riziko útoků DoS (DoS) omezením rychlosti zpracování požadavků, nejedná se o komplexní řešení útoků DDoS (Distributed Denial of Service). Útoky DDoS zahrnují více systémů, které aplikaci zahlcují záplavou požadavků, což ztěžuje zpracování pomocí omezování rychlosti.
Pro robustní ochranu před útoky DDoS zvažte použití komerční služby ochrany před útoky DDoS. Tyto služby nabízejí pokročilé funkce, jako jsou:
- analýza provozu: Průběžné monitorování a analýza příchozího provozu za účelem zjišťování a zmírnění útoků DDoS v reálném čase.
- škálovatelnosti: Schopnost zpracovávat rozsáhlé útoky prostřednictvím distribuce provozu napříč několika servery a datovými centry.
- automatizované zmírnění: Mechanismy automatizované reakce, které rychle blokují škodlivý provoz bez ručního zásahu.
- globální sítě: Globální síť serverů pro absorbování a zmírnění útoků blíže ke zdroji.
- konstantní aktualizace: Komerční služby nepřetržitě sledují a aktualizují své mechanismy ochrany tak, aby se přizpůsobily novým a vyvíjejícím hrozbám.
Při použití služby hostování cloudu je ochrana před útoky DDoS obvykle k dispozici jako součást hostitelského řešení, jako je firewall webových aplikací Azure, AWS Shield nebo Google Cloud Armor. Vyhrazené ochrany jsou k dispozici jako firewally webových aplikací (WAF) nebo jako součást řešení CDN, jako je Cloudflare nebo Akamai Kona Site Defender
Implementace komerční služby ochrany před útoky DDoS ve spojení s omezováním rychlosti může poskytnout komplexní strategii ochrany, zajištění stability, zabezpečení a výkonu aplikace.
Použití middleware pro omezování rychlosti
Následující kroky ukazují, jak používat middleware pro omezování rychlosti v aplikaci ASP.NET Core:
- Nakonfigurujte služby omezování rychlosti.
V souboru Program.cs nakonfigurujte služby omezování rychlosti přidáním příslušných zásad omezování rychlosti. Zásady se dají definovat buď jako globální, nebo pojmenované zásady. Následující příklad umožňuje 10 požadavků za minutu podle uživatele (identity) nebo globálně:
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)
}));
});
Pojmenované zásady je potřeba explicitně použít na stránky nebo koncové body. Následující příklad přidá pevné omezení oken pod názvem "fixed", které následně přidáme do koncového bodu:
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();
Globální limiter se použije na všechny koncové body automaticky, když je konfigurován prostřednictvím možností . GlobalLimiter.
Povolit middleware pro omezování rychlosti
Ve souboru
Program.cspovolte middleware omezování rychlosti voláním UseRateLimiter:
app.UseRouting();
app.UseRateLimiter();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run();
Použití zásad omezování rychlosti na koncové body nebo stránky
Použití omezování rychlosti u koncových bodů WebAPI
Použijte pojmenovanou zásadu na koncový bod nebo skupinu, například:
app.MapGet("/api/resource", () => "This endpoint is rate limited")
.RequireRateLimiting("fixed"); // Apply specific policy to an endpoint
Použití omezování rychlosti na kontrolery MVC
Použijte nakonfigurované zásady omezování rychlosti na konkrétní koncové body nebo globálně. Pokud chcete například použít "pevné" zásady pro všechny koncové body kontroleru:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireRateLimiting("fixed");
});
Přidat omezování rychlosti pro serverové aplikace Blazor
K nastavení omezování rychlosti pro všechny směrovatelné komponenty aplikace Razor zadejte RequireRateLimiting s názvem politika omezování rychlosti pro volání MapRazorComponents v souboru Program. V následujícím příkladu se použije zásada omezování rychlosti s názvem "policy":
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.RequireRateLimiting("policy");
Pokud chcete nastavit zásadu pro jednu směrovatelnou komponentu Razor nebo složku komponent prostřednictvím souboru _Imports.razor, použije se [EnableRateLimiting] atribut s názvem zásady. V následujícím příkladu se použije zásada omezování rychlosti s názvem "override". Zásada nahrazuje všechny zásady, které se aktuálně vztahují na koncový bod. Globální limiter se stále spouští na koncovém bodu, kde je tento atribut použit.
@page "/counter"
@using Microsoft.AspNetCore.RateLimiting
@attribute [EnableRateLimiting("override")]
<h1>Counter</h1>
Atribut [EnableRateLimiting] se použije pouze u směrovatelné komponenty nebo složky komponent prostřednictvím souboru _Imports.razor, pokud se na RequireRateLimitingnevolá .
Atribut [DisableRateLimiting] slouží k zakázání omezování rychlosti pro směrovatelnou komponentu nebo složku komponent prostřednictvím souboru _Imports.razor.
Algoritmy omezování rychlosti
Třída RateLimiterOptionsExtensions poskytuje následující rozšiřující metody pro omezování rychlosti:
Pevné, posuvné a tokenové omezovače omezují maximální počet požadavků v časovém období. Limiter souběžnosti omezuje pouze počet souběžných požadavků a neskončuje počet požadavků v časovém období. Náklady na koncový bod by se měly zvážit při výběru limiteru. Náklady na koncový bod zahrnují použité prostředky, například čas, přístup k datům, procesor a vstupně-výstupní operace.
Pevný okenní omezovač
Metoda AddFixedWindowLimiter používá k omezení požadavků pevný časový interval. Po vypršení časového intervalu se spustí nové časové okno a limit požadavku se resetuje.
Uvažujte následující kód:
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();
Předchozí kód:
- Volá AddRateLimiter, aby přidal službu omezování rychlosti do kolekce služeb.
- Volá
AddFixedWindowLimiterk vytvoření pevného omezovače oken s názvem"fixed"a nastaví: - PermitLimit až 4 a čas Window do 12. Je povoleno maximálně 4 požadavky na každé 12sekundové okno.
- QueueProcessingOrder na OldestFirst.
- QueueLimit na hodnotu 2 (nastavte na hodnotu 0, pokud chcete zakázat mechanismus zařadování do fronty).
- Volání UseRateLimiter za účelem povolení omezování rychlosti.
Aplikace by měly používat konfiguraci k nastavení možností omezovače. Následující kód aktualizuje předchozí kód pomocí MyRateLimitOptions k aktualizaci konfigurace:
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 musí být voláno po UseRouting, když se používají rozhraní API pro omezení rychlosti specifická pro koncové body. Pokud je například atribut [EnableRateLimiting] použit, musí být UseRateLimiter zavoláno po UseRouting. Pokud se volají pouze globální limitery, UseRateLimiter se může volat před UseRouting.
Posuvný omezovač oken
Algoritmus posuvného okna:
- Podobá se omezovači pevných oken, ale přidává segmenty na každé okno. Okno se posune o jeden segment při každém intervalu segmentů. Interval segmentu je (čas okna)/(segmenty na okno).
- Omezuje počet požadavků na okno na
permitLimit. - Každé časové okno je rozděleno do
nsegmentů na každé okno. - Žádosti převzaté z časového segmentu vypršeného o jedno okno zpět (
nsegmenty před aktuálním segmentem) se přidají do aktuálního segmentu. Jako segment s vypršenou platností označujeme nejstarší časový úsek, který je o jedno okno zpět.
Podívejte se na následující tabulku, která ukazuje omezovač posuvného okna s 30sekundovým oknem, třemi segmenty na okno a limitem 100 požadavků:
- Horní řádek a první sloupec znázorňují časový segment.
- Druhý řádek zobrazuje zbývající dostupné žádosti. Zbývající požadavky se počítají jako dostupné požadavky minus zpracované požadavky a recyklované žádosti.
- Žádosti se v každém okamžiku pohybují podél diagonální modré čáry.
- Od 30. okamžiku se žádost převzatá z časového segmentu s vypršenou platností přidá zpět do limitu požadavku, jak je znázorněno na červených řádcích.
Následující tabulka ukazuje data v předchozím grafu v jiném formátu. Sloupec K dispozici zobrazuje požadavky, které jsou dostupné z předchozího segmentu (přenos z předchozího řádku). První řádek zobrazuje 100 dostupných požadavků, protože neexistuje žádný předchozí segment.
| Čas | dostupný | Obsazený | Recyklováno z prošlých | Přenést |
|---|---|---|---|---|
| 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 |
Následující kód používá omezovač rychlosti posuvného okna:
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();
Omezovač kontejnerů tokenů
Limitátor kontejneru tokenů je podobný klouzavému omezovači oken, ale místo přidání žádostí přijatých z segmentu s vypršenou platností se každý interval doplňování přidá pevný počet tokenů. Přidané tokeny v jednotlivých segmentech nemohou zvýšit dostupné tokeny na číslo vyšší než limit vědra tokenů. Následující tabulka ukazuje limit kontejneru tokenů s limitem 100 tokenů a 10sekundovým doplňovacím obdobím.
| Čas | dostupný | Obsazený | Přidáno | Přenést |
|---|---|---|---|---|
| 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 |
Následující kód používá omezovač kontejneru tokenů:
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();
Když je AutoReplenishment nastaven na true, vnitřní časovač doplňuje tokeny každých ReplenishmentPeriod; když je nastaven na false, aplikace musí volat TryReplenish na limitator.
Omezovač souběžnosti
Limiter souběžnosti omezuje počet souběžných požadavků. Každý požadavek snižuje limit souběžnosti o jeden. Po dokončení žádosti se limit zvýší o jeden. Na rozdíl od ostatních omezovačů požadavků, které omezují celkový počet požadavků na zadané období, limiter souběžnosti omezuje pouze počet souběžných požadavků a nesdílí počet požadavků v časovém období.
Následující kód používá limiter souběžnosti:
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();
Omezování rychlosti – partice
Oddíly omezování rychlosti rozdělují provoz do samostatných segmentů, které získají vlastní počítadla limitů rychlosti. To umožňuje podrobnější řízení než jeden globální čítač. Partiční segmenty jsou definované různými klíči (například ID uživatele, IP adresa nebo API klíč).
Výhody dělení
- Spravedlnost: Jeden uživatel nemůže spotřebovat celý limit rychlosti na úkor ostatních
- Granularita: Různá omezení pro různé uživatele a prostředky
- zabezpečení: Lepší ochrana před cílovým zneužitím
- vrstvené služby: Podpora úrovní služby s různými limity
Omezení dělené rychlosti poskytuje jemně odstupňovanou kontrolu nad tím, jak spravujete provoz rozhraní API a zároveň zajišťuje spravedlivé přidělování prostředků.
Podle IP adresy
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 50,
Window = TimeSpan.FromMinutes(1)
}));
Podle uživatele Identity
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.User.Identity?.Name ?? "anonymous",
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
}));
Pomocí klíče rozhraní API
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)
}),
};
});
Podle cesty ke koncovému bodu
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)
});
});
Vytváření zřetězených omezovačů
Rozhraní CreateChained API umožňuje předávání více PartitionedRateLimiter , které jsou sloučeny do jednoho PartitionedRateLimiter. Kombinovaný limiter spouští všechny vstupní limitery v posloupnosti.
Následující kód používá CreateChained:
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();
Další informace najdete ve zdrojovém kódu CreateChained.
Volba toho, co se stane, když je požadavek omezený rychlostí
V jednoduchých případech stačí nastavit stavový kód:
builder.Services.AddRateLimiter(options =>
{
// Set a custom status code for rejections
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
// Rate limiter configuration...
});
Nejběžnějším přístupem je registrace zpětného volání OnRejected při konfiguraci limitování rychlosti.
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);
};
});
Další možností je zařadit žádost do fronty:
Řazení front žádostí
Pokud je povoleno řazení do fronty, při překročení rychlostního limitu se požadavek zařadí do fronty, kde čeká, dokud není k dispozici povolení nebo dokud nevyprší časový limit. Požadavky se zpracovávají podle pořadí ve frontě, které lze konfigurovat.
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 a DisableRateLimiting atributy
Atributy [EnableRateLimiting] a [DisableRateLimiting] lze použít u kontroleru, metody akce nebo Razor Stránky. U Razor stránek musí být atribut použit na Razor stránku, nikoli na obslužné rutiny.
[EnableRateLimiting] Například nelze použít pro OnGet, OnPostani pro žádnou jinou obslužnou rutinu stránky.
Atribut [DisableRateLimiting]zakáže omezení rychlosti kontroleru, metody akce nebo Razor stránky bez ohledu na pojmenované omezovače rychlosti nebo globální limitery použité. Představte si například následující kód, který volá RequireRateLimiting aby se rychlostní omezení použilo fixedPolicy na všechny koncové body kontroleru.
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();
V následujícím kódu [DisableRateLimiting] deaktivuje omezení rychlosti a přepíše nastavení [EnableRateLimiting("fixed")], které se použije na Home2Controller a app.MapDefaultControllerRoute().RequireRateLimiting(fixedPolicy) volané v Program.cs:
[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 });
}
}
V předchozím kódu se [EnableRateLimiting("sliding")]nepoužije na metodu akce Privacy, protože byla Program.cs volána app.MapDefaultControllerRoute().RequireRateLimiting(fixedPolicy).
Zvažte následující kód, který nezavolá na RequireRateLimiting na MapRazorPages nebo MapDefaultControllerRoute:
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();
Vezměte v úvahu následující kontroler:
[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 });
}
}
V předchozím kontroleru:
- Omezení rychlosti zásad
"fixed"je použito na všechny metody akcí, které nemají atributyEnableRateLimitingaDisableRateLimiting. - Na
"sliding"akci je aplikovánPrivacyomezovač rychlosti zásad. - Omezení rychlosti je u metody akce
NoLimitzakázáno.
Metriky omezování rychlosti
Middleware pro omezování rychlosti poskytuje integrované metriky a možnosti monitorování, které pomáhají pochopit, jak omezení rychlosti ovlivňují výkon aplikací a uživatelské prostředí. Seznam metrik najdete v Microsoft.AspNetCore.RateLimiting.
Testování koncových bodů s omezením rychlosti
Před nasazením aplikace pomocí omezování rychlosti do produkčního prostředí otestujte aplikaci a ověřte použité omezení rychlosti a možnosti. Vytvořte například skript JMeter pomocí nástroje, jako je BlazeMeter nebo Apache JMeter HTTP(S) Test Script Recorder a načtěte skript do služby Azure Load Testing.
Vytváření oddílů se vstupem uživatele způsobí, že aplikace bude zranitelná vůči útokům DoS (Denial of Service ). Vytváření oddílů na IP adresách klienta například způsobí, že aplikace bude zranitelná vůči útokům na dostupnost služby, které využívají falšování identity zdrojové IP adresy. Další informace najdete v tématu BCP 38 RFC 2827 Filtrování příchozího přenosu dat sítě: Porazit útoky na odepření služeb, které využívají falšování identity zdrojové IP adresy.
Další materiály
- Middleware pro omezování rychlosti od Maartena Balliauwa poskytuje vynikající úvod a přehled omezování rychlosti.
- Omezení rychlosti obslužné rutiny HTTP v .NET