Introducción a la Limitación de Tasa en Aplicaciones Web
La limitación de tasa (rate limiting) es una técnica esencial para proteger las API web y los servicios de abusos, sobrecargas o ataques de denegación de servicio (DoS). Al restringir el número de solicitudes que un cliente puede realizar dentro de un período de tiempo determinado, se asegura la disponibilidad y estabilidad del servicio para todos los ussuarios. En el ecosistema de .NET Core, la biblioteca AspNetCoreRateLimit ofrece una solución robusta y flexible para implementar esta funcionalidad.
Este artículo detalla cómo configurar y utilizar AspNetCoreRateLimit en un proyecto .NET 6 para establecer límites de solicitud basados en la dirección IP del cliente, ofreciendo un control granular sobre el acceso a los recursos de su API.
- Instalación del Paquete NuGet
Para comenzar, añada el paquete AspNetCoreRateLimit a su proyecto .NET 6. Esto se puede hacer a través del Administrador de Paquetes NuGet de Visual Studio, la CLI de .NET o editando directamente el archivo .csproj:
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
Este paquete provee la infraestructura necesaria para implementar políticas de limitación de tasa.
- Configuración de Servicios en Program.cs
La configuración de AspNetCoreRateLimit se realiza en el archivo Program.cs, donde se registran los servicios y se integra el midddleware en el pipeline de la aplicación. Es crucial configurar un almacenamiento para los contadores de solicitudes y definir cómo se cargan las reglas.
using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.OpenApi.Models; // Para Swagger, si se usa
var appBuilder = WebApplication.CreateBuilder(args);
// --- Configuración de servicios de AspNetCoreRateLimit ---
// 1. Almacenamiento en caché en memoria para los contadores de solicitudes.
// Para entornos de producción con múltiples instancias, se recomienda un almacenamiento distribuido.
appBuilder.Services.AddMemoryCache();
// 2. Cargar las opciones generales de limitación de tasa desde 'appsettings.json'.
appBuilder.Services.Configure<IpRateLimitOptions>(appBuilder.Configuration.GetSection("IpRateLimiting"));
// 3. Cargar las políticas de limitación de tasa específicas desde 'appsettings.json'.
appBuilder.Services.Configure<IpRateLimitPolicies>(appBuilder.Configuration.GetSection("IpRateLimitPolicies"));
// 4. Registrar la implementación de la limitación de tasa en memoria.
// Como alternativa, se pueden usar implementaciones distribuidas como AddDistributedRateLimiting
// con Redis o SQL Server para arquitecturas escalables.
appBuilder.Services.AddInMemoryRateLimiting();
// 5. Registrar servicios esenciales para el correcto funcionamiento de AspNetCoreRateLimit.
appBuilder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
appBuilder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
// --- Otros servicios estándar de ASP.NET Core ---
appBuilder.Services.AddControllers();
appBuilder.Services.AddEndpointsApiExplorer(); // Habilitar API Explorer para Swagger/OpenAPI
appBuilder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API de Prueba de Flujo", Version = "v1" });
// Se pueden añadir más configuraciones de Swagger aquí, como comentarios XML o seguridad JWT.
});
var webApp = appBuilder.Build();
// --- Integración del middleware de AspNetCoreRateLimit ---
// Habilitar el middleware de limitación de tasa de IP.
// Debe registrarse ANTES de cualquier middleware que pueda generar respuestas de error
// o que se quiera proteger.
webApp.UseIpRateLimiting();
// --- Middleware estándar de ASP.NET Core ---
if (webApp.Environment.IsDevelopment())
{
webApp.UseSwagger();
webApp.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API de Prueba de Flujo v1");
});
}
// webApp.UseHttpsRedirection(); // Se puede habilitar si se desea
webApp.UseAuthorization(); // Habilitar si la aplicación utiliza autenticación/autorización
webApp.MapControllers(); // Mapea los controladores a las rutas de la API
webApp.Run();
En este código, se configura AddMemoryCache para almacenar los contadores de solicitudes, se vinculan las secciones IpRateLimiting y IpRateLimitPolicies del archivo de configuración a sus respectivas clases de opciones, y se registra AddInMemoryRateLimiting. Es fundamental registrar también IHttpContextAccessor y IRateLimitConfiguration como servicios singleton.
- Definición de Políticas de Limitación en appsettings.json
Las reglas de limitación de tasa se definen en el archivo appsettings.json. Esto permite una gestión flexible y sin necesidad de recompilar el código al cambiar las políticas.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IpRateLimiting": {
// Si es 'true', las reglas se aplicarán a endpoints específicos (ej: GET:/api/recurso).
// Si es 'false' (valor por defecto), las reglas generales se aplicarán globalmente.
"EnableEndpointRateLimiting": false,
// Si es 'true', las solicitudes bloqueadas se contarán en el límite de tasa.
"StackBlockedRequests": false,
// Encabezado HTTP para identificar la IP real del cliente (útil detrás de proxies/balanceadores de carga).
"RealIpHeader": "X-Real-IP",
// Encabezado HTTP para identificar a un cliente específico (ej: una clave de API).
"ClientIdHeader": "X-ClientId",
// Código de estado HTTP por defecto para respuestas de "demasiadas solicitudes".
"HttpStatusCode": 429,
// Respuesta personalizada cuando se excede la cuota.
"QuotaExceededResponse": {
"Content": "{ \"status\": 429, \"mensaje\": \"Demasiadas solicitudes. Por favor, inténtelo de nuevo más tarde.\" }",
"ContentType": "application/json",
"StatusCode": 429
},
// Lista de direcciones IP que estarán exentas de cualquier limitación.
"IpWhitelist": [
"127.0.0.1",
"::1" // IPv6 localhost
],
// Lista de endpoints que estarán exentos de limitación (ej: GET:/api/health).
"EndpointWhitelist": [],
// Lista de IDs de cliente (del ClientIdHeader) que estarán exentos de limitación.
"ClientWhitelist": [],
// Reglas generales que se aplican a todos los clientes por defecto.
"GeneralRules": [
{
"Endpoint": "*", // Aplica a todos los endpoints.
"Period": "5s", // Período de 5 segundos.
"Limit": 3 // Límite de 3 solicitudes en 5 segundos.
},
{
"Endpoint": "*",
"Period": "1m", // Período de 1 minuto.
"Limit": 20 // Límite de 20 solicitudes en 1 minuto.
}
]
},
"IpRateLimitPolicies": {
// Definición de reglas de limitación de tasa específicas por IP o rango de IPs.
"IpRules": [
{
// Dirección IP específica o rango CIDR.
"Ip": "84.247.85.224",
"Rules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 5 // 5 solicitudes por segundo para esta IP.
},
{
"Endpoint": "*",
"Period": "10m",
"Limit": 100 // 100 solicitudes en 10 minutos para esta IP.
}
]
},
{
// Ejemplo de rango de IPs (subnet CIDR).
"Ip": "192.168.3.0/24",
"Rules": [
{
"Endpoint": "GET:/api/data", // Regla específica para un método y endpoint.
"Period": "5s",
"Limit": 1 // 1 solicitud en 5 segundos para este endpoint desde este rango.
},
{
"Endpoint": "*",
"Period": "1h",
"Limit": 300 // 300 solicitudes por hora para cualquier endpoint desde este rango.
}
]
}
]
}
}
En este ejemplo, se configuran dos secciones principales:
IpRateLimiting: Contiene configuraciones generales como la habiltiación de límites por endpoint, el encabezado para obtener la IP real (X-Real-IPes común cuando se usa un proxy inverso), y una respuesta personalizada cuando se excede la cuota. LasGeneralRulesaplican a todos los clientes que no tienen una política específica.IpRateLimitPolicies: Permite definir reglas de limitación específicas para direcciones IP o rangos de IP (notación CIDR). Cada regla puede especificar unEndpoint(*para todos), unPeriod(ej: "1s", "5m", "1h") y unLimit.
Es importante destacar que el StatusCode en QuotaExceededResponse debe coincidir con HttpStatusCode para una respuesta coherente, siendo el 429 Too Many Requests el estándar para esta situación.