π‘️ Security in .NET: Preventing DoS with Rate Limiting
Even the most secure API is useless if it’s offline. A Denial of Service (DoS) attack occurs when an attacker floods your API with thousands of requests per second, exhausting your server's CPU and Memory.
In .NET 8, we can prevent this by implementing Rate Limiting—a strategy that restricts how many requests a specific user or IP address can make within a given timeframe.
1️⃣ The "Fixed Window" Strategy
The most common approach is the Fixed Window. Imagine a 60-second window:
- A user is allowed 50 requests.
- If they hit request #51 at 59 seconds, they are blocked.
- At 60 seconds, the counter resets to zero.
This ensures that no single client can monopolize your server's resources.
2️⃣ Implementation in .NET 8
We configure the Rate Limiter in Program.cs. In this example, we partition the limits by the User's IP Address so that one "bad actor" doesn't block legitimate users.
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;
#region RATE LIMITING (.NET 8)
builder.Services.AddRateLimiter(options =>
{
// Configure what happens when a user is rejected
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
options.AddPolicy("api", context =>
RateLimitPartition.GetFixedWindowLimiter(
// Partition by IP Address: Each IP gets its own unique "bucket"
partitionKey: context.Connection.RemoteIpAddress?.ToString(),
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 50, // Max 50 requests
Window = TimeSpan.FromMinutes(1), // Per 1 minute
QueueLimit = 2, // Small buffer for simultaneous bursts
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
}));
});
#endregion
3️⃣ Applying the Policy
Once registered, you must apply the middleware and the policy to your endpoints.
Globally for all Controllers:
var app = builder.Build();
app.UseRateLimiter(); // Must be placed before MapControllers
app.MapControllers().RequireRateLimiting("api");
app.Run();
Or to specific Controller Actions:
[HttpGet]
[EnableRateLimiting("api")]
public IActionResult GetProducts()
{
return Ok(_products);
}
π§© Understanding the Parameters
- PermitLimit: The maximum number of requests allowed in the window.
- Window: The duration before the counter resets.
- QueueLimit: If a user hits the limit, should you drop the request immediately or let a few wait in line? (2 is a safe, conservative number).
- RejectionStatusCode: We use 429 Too Many Requests, the standard HTTP signal to a client that they need to slow down.
π‘️ Why This is a "Must-Have" Security Layer
- Protection Against Brute Force: If an attacker is trying to guess a password on your /login endpoint, Rate Limiting slows them down significantly, making the attack practically impossible.
- Cost Control: If you are using cloud services (like Azure or AWS) where you pay for compute time or data transfer, Rate Limiting prevents a massive bill caused by a malicious bot scrape.
- Fair Usage: It ensures that a single heavy user doesn't degrade the performance of the API for everyone else.
π The "Fort Knox" Security Stack So Far
| Layer | Technology | Protection |
|---|---|---|
| Input | HtmlSanitizer | Prevents XSS (Malicious Scripts) |
| Browser | CSP Headers | Prevents Script Execution & Data Leaks |
| Transport | HSTS | Enforces HTTPS Encryption |
| Availability | Rate Limiting | Prevents DoS & Brute Force |
π Final Thoughts
Security is about more than just data integrity; it's about availability. By implementing the .NET 8 Rate Limiter, you ensure your application remains responsive and resilient under pressure.
If your API is behind a Load Balancer or Proxy (like Nginx or Cloudflare), make sure your app is configured to read the
X-Forwarded-For header, otherwise RemoteIpAddress will always be the IP of your proxy!
Comments
Post a Comment