Brute Force in Aspnet
How Brute Force Manifests in Aspnet
In ASP.NET Core applications, brute force attacks most commonly target authentication endpoints like /api/auth/login or /api/auth/password-reset. Attackers use automated tools (e.g., Hydra, Burp Intruder) to rapidly iterate through credential pairs or token guesses, exploiting the absence of request throttling. The vulnerability arises when developers implement authentication logic (often via IAuthenticationService or custom Authorize attributes) without coupling it to ASP.NET Core's rate limiting infrastructure.
A typical vulnerable pattern is a login controller that validates credentials against a database but lacks any per-IP or per-user request constraints:
[HttpPost("login")]
public async Task Login([FromBody] LoginDto dto)
{
var user = await _userManager.FindByNameAsync(dto.Username);
if (user != null && await _userManager.CheckPasswordAsync(user, dto.Password))
{
// Generate token...
return Ok(new { token = _tokenService.Generate(user) });
}
return Unauthorized();
} Without rate limiting, an attacker can send thousands of requests per minute from a single IP or across a botnet. This can lead to credential stuffing (using breached credential pairs) or password spraying (trying common passwords across many accounts). In ASP.NET applications using IdentityFramework, the SignInManager does not inherently throttle failed attempts unless explicitly configured with LockoutOnFailure—and even then, lockout policies are user-account-specific, not IP-based, leaving the endpoint itself exposed to volumetric attacks.
Another manifestation occurs in password reset or account recovery flows. If a POST /api/auth/forgot-password endpoint accepts an email and triggers a reset email without limiting requests, attackers can enumerate valid email addresses by monitoring response times or error messages, or flood users with emails (a denial-of-service vector).
Aspnet-Specific Detection
Detecting brute force vulnerabilities in ASP.NET APIs involves identifying endpoints that accept authentication-sensitive data (credentials, tokens, email addresses) and verifying the absence of rate limiting. Manual testing requires sending rapid, repeated requests to such endpoints and observing if responses become throttled (e.g., HTTP 429 Too Many Requests) or if the server imposes any delay.
middleBrick automates this detection during its black-box scan. For an ASP.NET API, it first identifies candidate endpoints by parsing OpenAPI/Swagger specs for parameters like username, password, email, or token. Then, it sends a series of crafted requests (e.g., 20 rapid POSTs with invalid credentials) to each candidate. If all requests return 200 or 401 without any 429 status or Retry-After header, the scanner flags a missing rate limit. The scan also checks for the presence of ASP.NET Core's rate limiting middleware by looking for response headers like X-RateLimit-Limit or X-RateLimit-Remaining.
For example, scanning an ASP.NET API with a vulnerable login endpoint yields a middleBrick finding under the Rate Limiting category:
| Finding | Severity | Endpoint |
|---|---|---|
| No rate limiting detected on authentication endpoint | High | POST /api/auth/login |
The report includes remediation guidance specific to ASP.NET Core, such as enabling the built-in rate limiter. The scanner's 12 parallel checks include this test, and the overall security score (A–F) will reflect the absence of such protections, typically resulting in a High severity finding for any public-facing auth API.
Aspnet-Specific Remediation
ASP.NET Core provides robust, configurable rate limiting via the Microsoft.AspNetCore.RateLimiting package (available since .NET 7). The remediation involves three steps: add the middleware, define policies, and apply them to vulnerable endpoints.
1. Add the Rate Limiter Service
In Program.cs (or Startup.cs), register the rate limiter with a global policy or specific named policies:
builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("AuthPolicy", context =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? context.User.Identity?.Name,
factory: partition => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 5, // 5 requests
QueueLimit = 0,
Window = TimeSpan.FromMinutes(1)
}));
options.OnRejected = async (context, token) =>
{
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
await context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.", token);
};
});2. Apply the Policy to Endpoints
Use the [EnableRateLimiting] attribute on controllers or actions. For login and password reset endpoints:
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
[HttpPost("login")]
[EnableRateLimiting("AuthPolicy")]
public async Task Login([FromBody] LoginDto dto)
{
// ... existing logic
}
[HttpPost("forgot-password")]
[EnableRateLimiting("AuthPolicy")]
public async Task ForgotPassword([FromBody] ForgotPasswordDto dto)
{
// ... existing logic
}
} 3. Consider Additional Layers
For user-account-based limits (to prevent locking out legitimate users during an attack), combine with Identity's lockout features:
services.Configure(options =>
{
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
}); However, IP-based rate limiting (as shown above) is the primary defense against volumetric brute force. middleBrick's remediation guidance will explicitly recommend adding the AddRateLimiter middleware and applying policies to all authentication and credential-related endpoints. After implementation, a rescan should show the Rate Limiting check passing and the overall security score improving.
Frequently Asked Questions
Does middleBrick actually attempt brute force attacks during a scan?
Can middleBrick differentiate between missing rate limits and a WAF blocking the scan?
403 or 406 with a distinct body (e.g., 'Request blocked'). A missing rate limit returns consistent 200/401 responses for all invalid attempts. The scanner also checks for standard rate limit headers (X-RateLimit-*) that WAFs often add.