Perfecto. A continuación, te dejo una solución profesional y reutilizable para .NET 8: un middleware que detecta si el cliente proviene de una red local y, si no, marca el request como “requiere 2FA” o “requiere CAPTCHA”.
También se puede usar en un filtro de acción, si prefieres aplicar la lógica solo en controladores específicos.
OBJETIVO
- Detectar si la IP del cliente está en una red de confianza.
- Marcar el request como requiere seguridad adicional.
- Usar esto en endpoints REST API para tomar decisiones (ej. pedir 2FA o CAPTCHA).
Middleware global (ideal para APIs públicas)
1. Instala dependencia para validar rangos CIDR:
dotnet add package IPNetwork2
2. Crea el middleware
// Middlewares/TrustedNetworkMiddleware.cs using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using NetTools; public class TrustedNetworkMiddleware { private readonly RequestDelegate _next; private readonly List<IPAddressRange> _trustedRanges; public TrustedNetworkMiddleware(RequestDelegate next, IEnumerable<string> trustedCidrs) { _next = next; _trustedRanges = trustedCidrs.Select(IPAddressRange.Parse).ToList(); } public async Task InvokeAsync(HttpContext context) { var ip = ObtenerIpCliente(context); if (ip is not null && EsIpConfiable(ip)) { context.Items["EsRedConfiable"] = true; } else { context.Items["EsRedConfiable"] = false; } await _next(context); } private static IPAddress? ObtenerIpCliente(HttpContext context) { var forwarded = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (!string.IsNullOrEmpty(forwarded) && IPAddress.TryParse(forwarded, out var ipF)) return ipF; return context.Connection.RemoteIpAddress; } private bool EsIpConfiable(IPAddress ip) { return _trustedRanges.Any(r => r.Contains(ip)); } }
3. Extensión para Program.cs
public static class TrustedNetworkMiddlewareExtensions { public static IApplicationBuilder UseTrustedNetworkDetection(this IApplicationBuilder app, IEnumerable<string> trustedCidrs) { return app.UseMiddleware<TrustedNetworkMiddleware>(trustedCidrs); } }
4. En Program.cs
(antes de MapControllers
)
var app = builder.Build(); var redesConfiables = new[] { "192.168.0.0/16", "10.0.0.0/8", "172.16.0.0/12", "TU_RED_CORPORATIVA_PUBLICA/24" }; app.UseTrustedNetworkDetection(redesConfiables);
5. Uso en tus controladores
[HttpPost("login")] public IActionResult Login([FromBody] LoginRequest request) { var esRedConfiable = HttpContext.Items["EsRedConfiable"] as bool? ?? false; if (esRedConfiable) { // Saltar CAPTCHA o 2FA return Ok(new { token = GenerarJwt() }); } // Requiere paso adicional return Ok(new { requiere2fa = true, requiereCaptcha = true }); }
Alternativa: Filtro de acción para ciertos endpoints
Úsalo si solo quieres aplicar esta lógica en controladores específicos:
public class SoloRedConfiableAttribute : ActionFilterAttribute { private readonly List<IPAddressRange> _trustedRanges; public SoloRedConfiableAttribute(string[] trustedCidrs) { _trustedRanges = trustedCidrs.Select(IPAddressRange.Parse).ToList(); } public override void OnActionExecuting(ActionExecutingContext context) { var ip = context.HttpContext.Connection.RemoteIpAddress; var esConfiable = ip != null && _trustedRanges.Any(r => r.Contains(ip)); if (!esConfiable) { context.Result = new ForbidResult(); // o Unauthorized, según el caso } } }
Uso:
[HttpPost("solo-red-local")] [ServiceFilter(typeof(SoloRedConfiableAttribute), Arguments = new object[] { new[] { "192.168.0.0/16" } })] public IActionResult SoloRedLocal() { return Ok("Estás en red confiable"); }