Compartir a través de


Configuración de ASP.NET Core para trabajar con servidores proxy y equilibradores de carga

Nota:

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 9 de este artículo.

Advertencia

Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la directiva de compatibilidad de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.

Importante

Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Para la versión actual, consulte la versión de .NET 9 de este artículo.

Por Chris Ross

En la configuración recomendada de ASP.NET Core, la aplicación se hospeda mediante el módulo ASP.NET Core (ANCM), Nginx o Apache. Los servidores proxy, los equilibradores de carga y otros dispositivos de red con frecuencia ocultan información sobre la solicitud antes de que llegue a la aplicación:

  • Cuando las solicitudes HTTPS se redirigen mediante proxy a través de HTTP, el esquema original (HTTPS) se pierde y se debe reenviar en un encabezado.
  • Como una aplicación recibe una solicitud del proxy y no desde su verdadero origen en Internet o la red corporativa, la dirección IP del cliente de origen también se debe reenviar en el encabezado.

Esta información puede ser importante en el procesamiento de las solicitudes, por ejemplo, en los redireccionamientos, la autenticación, la generación de vínculos, la evaluación de directivas y la geolocalización del cliente.

Las aplicaciones diseñadas para ejecutarse en la granja de servidores web deben leer Hospedaje de ASP.NET Core en una granja de servidores web.

Encabezados reenviados

Por costumbre, los servidores proxy reenvían la información en encabezados HTTP.

Header Descripción
X-Forwarded-For (XFF) Contiene información sobre el cliente que inició la solicitud y los servidores proxy posteriores en una cadena de servidores proxy. Este parámetro puede contener direcciones IP y, opcionalmente, números de puerto. En una cadena de servidores proxy, el primer parámetro indica al cliente dónde se realizó primero la solicitud. Le siguen los identificadores de proxy posteriores. El último proxy en la cadena no se encuentra en la lista de parámetros. La última dirección IP del proxy y, opcionalmente, un número de puerto, está disponible como la dirección IP remota en la capa de transporte.
X-Forwarded-Proto (XFP) Valor del esquema de origen, HTTP o HTTPS. El valor también puede ser una lista de esquemas si la solicitud ha pasado por varios servidores proxy.
X-Forwarded-Host (XFH) El valor original del campo de encabezado de host. Por lo general, los servidores proxy no modifican el encabezado de host. Consulte Microsoft Security Advisory CVE-2018-0787 para información sobre una vulnerabilidad de elevación de privilegios que afecta a sistemas donde el proxy no valida ni restringe los encabezados de host a valores buenos conocidos.
X-Forwarded-Prefix Ruta de acceso base original solicitada por el cliente. Este encabezado puede ser útil para que las aplicaciones generen correctamente direcciones URL, redireccionamientos o vínculos al cliente.

El Middleware de encabezados reenviados, ForwardedHeadersMiddleware, lee estos encabezados y rellena los campos asociados en HttpContext.

El middleware realiza las siguientes actualizaciones:

Para obtener más información, consulte este problema de GitHub.

Se pueden configurar los valores predeterminados del Middleware de encabezados reenviados. Para la configuración predeterminada:

  • Solo hay un proxy entre la aplicación y el origen de las solicitudes.
  • Solo las direcciones de bucle invertido se configuran para servidores proxy conocidos y redes conocidas.
  • Los encabezados reenviados se denominan X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host y X-Forwarded-Prefix.
  • El valor de ForwardedHeaders es ForwardedHeaders.None. Los reenviadores deseados deben establecerse aquí para habilitar el middleware.

No todos los dispositivos de red agregan los encabezados X-Forwarded-For y X-Forwarded-Proto sin configuración adicional. Consulte las instrucciones del fabricante de su dispositivo si las solicitudes redirigidas mediante proxy no contienen estos encabezados cuando llegan a la aplicación. Si el dispositivo usa nombres de encabezado distintos a X-Forwarded-For y X-Forwarded-Proto, establezca las opciones ForwardedForHeaderName y ForwardedProtoHeaderName para que coincidan con los nombres de encabezado empleados por el dispositivo. Para obtener más información, vea Opciones del Middleware de encabezados reenviados y Configuración de un proxy que usa otros nombres de encabezado.

IIS o IIS Express y el módulo ASP.NET Core

El Middleware de encabezados reenviados se habilita de forma predeterminada mediante el Middleware de integración con IIS cuando la aplicación se hospeda fuera de proceso detrás de IIS y del módulo ASP.NET Core (ANCM). El Middleware de encabezados reenviados se activa para ejecutarse primero en la canalización de middleware con una configuración restringida específica del módulo ASP.NET Core. La configuración restringida se debe a problemas de confianza con encabezados reenviados, por ejemplo, suplantación de IP. El middleware está configurado para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto y está restringido a un único proxy localhost. Si se requiere configuración adicional, consulte la sección Opciones del Middleware de encabezados reenviados.

Otros escenarios de servidor proxy y equilibrador de carga

Al margen del uso de la integración con IIS al hospedar fuera de proceso, el Middleware de encabezados reenviados no está habilitado de forma predeterminada. El middleware de encabezados reenviados debe estar habilitado en una aplicación para procesar los encabezados reenviados con UseForwardedHeaders. Después de habilitar el middleware, si no se especifica ForwardedHeadersOptions para él, el valor predeterminado ForwardedHeadersOptions es ForwardedHeaders.None.

Configure el middleware con ForwardedHeadersOptions para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto.

Orden del middleware de encabezados reenviados

El Middleware de encabezados reenviados debe ejecutarse antes de otro middleware. Hacerlo en ese orden garantiza que el middleware que se basa en la información de encabezados reenviados pueda usar los valores de encabezado para procesarlos. El middleware de encabezados reenviados puede ejecutarse después del diagnóstico y el control de errores, pero siempre antes de llamar a UseHsts:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseForwardedHeaders();
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseForwardedHeaders();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Como alternativa, llame a UseForwardedHeaders antes del diagnóstico:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Nota

Si no se especifica ningún ForwardedHeadersOptions ni se aplica directamente en el método de extensión con UseForwardedHeaders, los encabezados predeterminados para reenviar son ForwardedHeadersOptions. La propiedad ForwardedHeaders debe estar configurada con los encabezados que se van a reenviar.

Configuración de Nginx

Para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto, vea X-Forwarded-For. Para obtener más información, consulte NGINX: Using the Forwarded header (NGINX: uso del encabezado Forwarded).

Configuración de Apache

X-Forwarded-For se agrega automáticamente. Para obtener más información, consulte Módulo de Apache mod_proxy: Encabezados de solicitud de proxy inverso.

Opciones del Middleware de encabezados reenviados

ForwardedHeadersOptions controla el comportamiento del ForwardedHeadersOptions. En el ejemplo siguiente se cambian los valores predeterminados:

  • Limita el número de entradas de los encabezados reenviados a 2.
  • Agrega una dirección de proxy conocida de 127.0.10.1.
  • Cambia el nombre del encabezado reenviado del valor predeterminado X-Forwarded-For a X-Forwarded-For-My-Custom-Header-Name.
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardLimit = 2;
    options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
    options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();
Opción Descripción
AllowedHosts Restringe los hosts por el encabezado X-Forwarded-Host a los valores proporcionados.
  • Los valores se comparan mediante ordinal-ignore-case.
  • Se deben excluir los números de puerto.
  • Si la lista está vacía, se permiten todos los hosts.
  • Un carácter comodín de nivel superior * permite que todos los hosts que no están vacíos.
  • Se permiten caracteres comodín de subdominio, pero no coinciden con el dominio raíz. Por ejemplo, *.contoso.com coincide con el subdominio foo.contoso.com pero no con el dominio raíz contoso.com.
  • Se permiten nombres de host Unicode, pero se convierten en Punycode para buscar la coincidencia.
  • Las direcciones IPv6 deben incluir corchetes de enlace y estar en formato convencional (por ejemplo, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Las direcciones IPv6 no usan mayúsculas y minúsculas de forma especial para buscar la igualdad lógica entre diferentes formatos, y no se realiza ninguna canonización.
  • Si no se restringen los hosts permitidos, un ciberdelincuente podría suplantar los vínculos generados por el servicio.
El valor predeterminado es un IList<string> vacío.
ForwardedForHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedForHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-For sino algún otro para reenviar la información.

De manera predeterminada, es X-Forwarded-For.
ForwardedHeaders Identifica qué reenviadores se deben procesar. Consulte ForwardedHeaders Enum para obtener la lista de campos que se aplican. Los valores típicos que se asignan a esta propiedad son ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

El valor predeterminado es ForwardedHeaders.None.
ForwardedHostHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedHostHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-Host sino algún otro para reenviar la información.

De manera predeterminada, es X-Forwarded-Host.
ForwardedProtoHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedProtoHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-Proto sino algún otro para reenviar la información.

De manera predeterminada, es X-Forwarded-Proto.
ForwardLimit Limita el número de entradas en los encabezados que se procesan. Establézcalo en null para deshabilitar el límite, pero esto solo se debe realizar si están configurados KnownProxies o KnownNetworks. Establecer un valor que no sea null es una medida de precaución (no una garantía) para protegerse contra los proxies mal configurados y las peticiones malintencionadas que llegan desde los canales laterales de la red.

El middleware de encabezados reenviados procesa los encabezados en orden inverso, de derecha a izquierda. Si se usa el valor predeterminado (1), solo se procesa el valor más a la derecha de los encabezados, a menos que se aumente el valor de ForwardLimit.

De manera predeterminada, es 1.
KnownNetworks Intervalos de direcciones de redes conocidas de los que se aceptan encabezados reenviados. Proporcione intervalos de direcciones IP mediante la notación de Enrutamiento de interdominios sin clases (CIDR).

Si el servidor usa sockets en modo dual, las direcciones IPv4 se suministran en formato IPv6 (por ejemplo, 10.0.0.1 en IPv4 se representa en IPv6 como ::ffff:10.0.0.1). Consulte IPAddress.MapToIPv6. Para determinar si este formato es necesario, examine HttpContext.Connection.RemoteIpAddress.

El valor predeterminado es un IList<IPNetwork> que contiene una única entrada para new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Direcciones de servidores proxy conocidos de los que se aceptan encabezados reenviados. Use KnownProxies para especificar las coincidencias exactas de direcciones IP.

Si el servidor usa sockets en modo dual, las direcciones IPv4 se suministran en formato IPv6 (por ejemplo, 10.0.0.1 en IPv4 se representa en IPv6 como ::ffff:10.0.0.1). Consulte IPAddress.MapToIPv6. Para determinar si este formato es necesario, examine HttpContext.Connection.RemoteIpAddress.

El valor predeterminado es un IList<IPAddress> que contiene una única entrada para IPAddress.IPv6Loopback.
OriginalForHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

De manera predeterminada, es X-Original-For.
OriginalHostHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

De manera predeterminada, es X-Original-Host.
OriginalProtoHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalProtoHeaderName.

De manera predeterminada, es X-Original-Proto.
RequireHeaderSymmetry Requiere que el número de valores de encabezado esté sincronizado entre los valores ForwardedHeadersOptions.ForwardedHeaders que se van a procesar.

El valor predeterminado en ASP.NET Core 1.x es true. El valor predeterminado en ASP.NET Core 2.0 o posterior es false.

Escenarios y casos de uso

Cuando no es posible agregar encabezados reenviados y todas las solicitudes son seguras

En algunos casos, puede que no sea posible agregar encabezados reenviados a las solicitudes redirigidas mediante proxy a la aplicación. Si el proxy está forzando a que todas las solicitudes externas públicas sean HTTPS, el esquema se puede establecer manualmente antes de usar cualquier tipo de middleware:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.Use((context, next) =>
{
    context.Request.Scheme = "https";
    return next(context);
});

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Este código puede deshabilitarse con una variable de entorno u otro valor de configuración en un entorno de desarrollo o ensayo:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

if (!app.Environment.IsProduction())
{
    app.Use((context, next) =>
    {
        context.Request.Scheme = "https";
        return next(context);
    });
}

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Trabajar con la ruta de acceso base y los servidores proxy que cambian la ruta de acceso de la solicitud

Algunos servidores proxy pasan la ruta de acceso sin cambios pero con una ruta de acceso base de aplicación que se debe quitar para que el enrutamiento funcione correctamente. El middleware UsePathBaseExtensions.UsePathBase divide la ruta de acceso en HttpRequest.Path y la ruta de acceso base de aplicación en HttpRequest.PathBase.

Si /foo es la ruta de acceso base de aplicación para una ruta de acceso de proxy que se pasa como /foo/api/1, el middleware establece Request.PathBase en /foo y Request.Path en /api/1 con el siguiente comando:

app.UsePathBase("/foo");
// ...
app.UseRouting();

Nota

Al usar WebApplication (consulte Migración de ASP.NET Core 5.0 a 6.0), app.UseRouting debe llamarse después de UsePathBase para que el middleware de enrutamiento pueda observar la ruta de acceso modificada antes de hacer coincidir las rutas. De lo contrario, las rutas coinciden antes de que UsePathBase reescriba la ruta de acceso, como se describe en los artículos Orden del middleware y Enrutamiento.

La ruta de acceso base y la ruta de acceso original se vuelven a aplicar cuando se llama de nuevo al middleware en orden inverso. Para más información sobre el procesamiento de pedidos de middleware, consulte Middleware de ASP.NET Core.

Si el proxy recorta la ruta de acceso (por ejemplo, el reenvío /foo/api/1 a /api/1), corrija los redireccionamientos y los vínculos mediante el establecimiento de la propiedad /foo/api/1 de la solicitud:

app.Use((context, next) =>
{
    context.Request.PathBase = new PathString("/foo");
    return next(context);
});

Si el proxy va a agregar datos de ruta de acceso, descarte parte de esta ruta para corregir los redireccionamientos y los vínculos; para ello, use StartsWithSegments y asígnelo a la propiedad Path:

app.Use((context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
    {
        context.Request.Path = remainder;
    }

    return next(context);
});

Configuración de un proxy que usa otros nombres de encabezado

Si el proxy no usa los encabezados denominados X-Forwarded-For y X-Forwarded-Proto para reenviar el puerto o la dirección de proxy y originar información de esquema, establezca las opciones ForwardedForHeaderName y ForwardedProtoHeaderName de modo que coincidan con los nombres de encabezado empleados por el proxy:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedForHeaderName = "HeaderNamUsedByProxy_X-Forwarded-For_Header";
    options.ForwardedProtoHeaderName = "HeaderNamUsedByProxy_X-Forwarded-Proto_Header";
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Reenvío del esquema para servidores proxy inversos Linux y que no son de IIS

Las aplicaciones que llaman a los métodos UseHttpsRedirection y UseHsts incluyen un sitio en un bucle infinito si se implementan en una instancia de Azure App Service de Linux, una máquina virtual Linux de Azure, o bien detrás de cualquier otro servidor proxy inverso, además de IIS. El servidor proxy inverso termina TLS y Kestrel no es consciente del esquema de solicitud correcto. En esta configuración también se produce un error de OAuth y OIDC, ya que generan redirecciones incorrectas. UseIISIntegration agrega y configura middleware de encabezados reenviados cuando se ejecuta detrás de IIS, pero no hay ninguna configuración automática coincidente para Linux (integración de Apache o Nginx).

Para reenviar el esquema desde el servidor proxy en escenarios que no sean de IIS, habilite Middleware de encabezados reenviados estableciendo ASPNETCORE_FORWARDEDHEADERS_ENABLED en true. Advertencia: Esta marca usa la configuración diseñada para entornos en la nube y no habilita características como KnownProxies option para restringir de qué direcciones IP se aceptan reenviadores.

Reenvío de certificados

Azure

Para configurar Azure App Service para el reenvío de certificados, consulte Configuración de la autenticación mutua de TLS en Azure App Service. La guía siguiente se aplica a la configuración de la aplicación de ASP.NET Core.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
    options.CertificateHeader = "X-ARR-ClientCert");

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Otros servidores proxy web

Si se usa un proxy que no es IIS ni Enrutamiento de solicitud de aplicaciones de Azure App Service, configure el proxy para reenviar el certificado que recibió en un encabezado HTTP.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
    options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Si el proxy no codifica en Base64 el certificado (como ocurre con Nginx), establezca la opción HeaderConverter. Considere el ejemplo siguiente:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
{
    options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
    options.HeaderConverter = (headerValue) =>
    {
        // Conversion logic to create an X509Certificate2.
        var clientCertificate = ConversionLogic.CreateAnX509Certificate2();
        return clientCertificate;
    };
});

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Solución de problemas

Cuando no se reenvíen los encabezados como estaba previsto, habilite el debug en nivel debug y el registro de la solicitud HTTP. UseHttpLogging debe llamarse después de UseForwardedHeaders:

using Microsoft.AspNetCore.HttpLogging;
using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddHttpLogging(options =>
{
    options.LoggingFields = HttpLoggingFields.RequestPropertiesAndHeaders;
});

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.UseForwardedHeaders();
app.UseHttpLogging();

app.Use(async (context, next) =>
{
    // Connection: RemoteIp
    app.Logger.LogInformation("Request RemoteIp: {RemoteIpAddress}",
        context.Connection.RemoteIpAddress);

    await next(context);
});

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Si hay varios valores en un encabezado determinado, el middleware de encabezados reenviados procesa los encabezados en orden inverso, de derecha a izquierda. El valor predeterminado de ForwardLimit es 1 (uno), por lo que solo el valor más a la derecha de los encabezados se procesa, a menos que se aumente el valor de ForwardLimit.

La dirección IP remota original de la solicitud debe coincidir con una entrada de las listas KnownProxies o KnownNetworks antes de procesar los encabezados reenviados. Esto limita la suplantación de encabezados al no aceptarse reenviadores de servidores proxy que no son de confianza. Cuando se detecta un servidor proxy desconocido, el registro indica la dirección de dicho proxy:

September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321

En el ejemplo anterior, 10.0.0.100 es un servidor proxy. Si se trata de un servidor proxy de confianza, agregue la dirección IP del servidor a KnownProxies o agregue una red de confianza a KnownNetworks. Para más información, vea la sección Opciones del Middleware de encabezados reenviados.

using Microsoft.AspNetCore.HttpOverrides;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseForwardedHeaders();
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseForwardedHeaders();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Para mostrar los registros, agregue "Microsoft.AspNetCore.HttpLogging": "Information" al archivo appsettings.Development.json:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.HttpLogging": "Information"
    }
  }
}

Importante

Admita solo las redes y los servidores proxy de confianza para reenviar encabezados. De lo contrario, se pueden producir ataques de suplantación de IP.

Recursos adicionales

En la configuración recomendada de ASP.NET Core, la aplicación se hospeda mediante IIS/módulo ASP.NET Core, Nginx o Apache. Los servidores proxy, los equilibradores de carga y otros dispositivos de red con frecuencia ocultan información sobre la solicitud antes de que llegue a la aplicación:

  • Cuando las solicitudes HTTPS se redirigen mediante proxy a través de HTTP, el esquema original (HTTPS) se pierde y se debe reenviar en un encabezado.
  • Como una aplicación recibe una solicitud del proxy y no desde su verdadero origen en Internet o la red corporativa, la dirección IP del cliente de origen también se debe reenviar en el encabezado.

Esta información puede ser importante en el procesamiento de las solicitudes, por ejemplo, en los redireccionamientos, la autenticación, la generación de vínculos, la evaluación de directivas y la geolocalización del cliente.

Encabezados reenviados

Por costumbre, los servidores proxy reenvían la información en encabezados HTTP.

Header Descripción
X-Forwarded-For Contiene información sobre el cliente que inició la solicitud y los servidores proxy posteriores en una cadena de servidores proxy. Este parámetro puede contener direcciones IP (y, opcionalmente, números de puerto). En una cadena de servidores proxy, el primer parámetro indica al cliente dónde se realizó primero la solicitud. Le siguen los identificadores de proxy posteriores. El último proxy en la cadena no se encuentra en la lista de parámetros. La última dirección IP del proxy y, opcionalmente, un número de puerto, está disponible como la dirección IP remota en la capa de transporte.
X-Forwarded-Proto El valor del esquema de origen (HTTP/HTTPS). El valor también puede ser una lista de esquemas si la solicitud ha pasado por varios servidores proxy.
X-Forwarded-Host El valor original del campo de encabezado de host. Por lo general, los servidores proxy no modifican el encabezado de host. Consulte Microsoft Security Advisory CVE-2018-0787 para información sobre una vulnerabilidad de elevación de privilegios que afecta a sistemas donde el proxy no valida ni restringe los encabezados de host a valores buenos conocidos.

El middleware de encabezados reenviados (ForwardedHeadersMiddleware) lee estos encabezados y rellena los campos asociados en HttpContext.

El middleware realiza las siguientes actualizaciones:

Para obtener más información, consulte este problema de GitHub.

Se pueden configurar los valores predeterminados del Middleware de encabezados reenviados. Para la configuración predeterminada:

  • Solo hay un proxy entre la aplicación y el origen de las solicitudes.
  • Solo las direcciones de bucle invertido se configuran para servidores proxy conocidos y redes conocidas.
  • Los encabezados reenviados se denominan X-Forwarded-For y X-Forwarded-Proto.
  • El valor de ForwardedHeaders es ForwardedHeaders.None. Los reenviadores deseados deben establecerse aquí para habilitar el middleware.

No todos los dispositivos de red agregan los encabezados X-Forwarded-For y X-Forwarded-Proto sin configuración adicional. Consulte las instrucciones del fabricante de su dispositivo si las solicitudes redirigidas mediante proxy no contienen estos encabezados cuando llegan a la aplicación. Si el dispositivo usa nombres de encabezado distintos a X-Forwarded-For y X-Forwarded-Proto, establezca las opciones ForwardedForHeaderName y ForwardedProtoHeaderName para que coincidan con los nombres de encabezado empleados por el dispositivo. Para obtener más información, vea Opciones del Middleware de encabezados reenviados y Configuración de un proxy que usa otros nombres de encabezado.

IIS o IIS Express y el módulo ASP.NET Core

El Middleware de encabezados reenviados se habilita de forma predeterminada mediante el Middleware de integración con IIS cuando la aplicación se hospeda fuera de proceso detrás de IIS y del módulo ASP.NET Core. El Middleware de encabezados reenviados está activado para ejecutarse primero en la canalización de middleware con una configuración restringida específica del módulo ASP.NET Core debido a problemas de confianza con los encabezados reenviados (por ejemplo, suplantación de IP). El middleware está configurado para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto y está restringido a un único proxy localhost. Si se requiere configuración adicional, consulte la sección Opciones del Middleware de encabezados reenviados.

Otros escenarios de servidor proxy y equilibrador de carga

Al margen del uso de la integración con IIS al hospedar fuera de proceso, el Middleware de encabezados reenviados no está habilitado de forma predeterminada. El middleware de encabezados reenviados debe estar habilitado en una aplicación para procesar los encabezados reenviados con UseForwardedHeaders. Después de habilitar el middleware, si no se especifica ForwardedHeadersOptions para él, el valor predeterminado ForwardedHeadersOptions es ForwardedHeaders.None.

Configure el middleware con ForwardedHeadersOptions para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto en Startup.ConfigureServices.

Orden del middleware de encabezados reenviados

El Middleware de encabezados reenviados debe ejecutarse antes de otro middleware. Hacerlo en ese orden garantiza que el middleware que se basa en la información de encabezados reenviados pueda usar los valores de encabezado para procesarlos. El middleware de encabezados reenviados puede ejecutarse después del diagnóstico y el control de errores, pero siempre antes de llamar a UseHsts:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.Configure<ForwardedHeadersOptions>(options =>
        {
            options.ForwardedHeaders =
                ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseForwardedHeaders();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseForwardedHeaders();
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Como alternativa, llame a UseForwardedHeaders antes del diagnóstico:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseForwardedHeaders();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Nota

Si no se especifica ningún ForwardedHeadersOptions en Startup.ConfigureServices o directamente en el método de extensión con UseForwardedHeaders, los encabezados predeterminados para reenviar son ForwardedHeadersOptions. La propiedad ForwardedHeaders debe estar configurada con los encabezados que se van a reenviar.

Configuración de Nginx

Para reenviar los encabezados X-Forwarded-For y X-Forwarded-Proto, vea X-Forwarded-For. Para obtener más información, consulte NGINX: Using the Forwarded header (NGINX: uso del encabezado Forwarded).

Configuración de Apache

X-Forwarded-For se agrega automáticamente. Vea X-Forwarded-For (Módulo de Apache mod_proxy: Encabezados de solicitud de proxy inverso).

Opciones del Middleware de encabezados reenviados

ForwardedHeadersOptions controla el comportamiento del middleware de encabezados reenviados. En el ejemplo siguiente se cambian los valores predeterminados:

  • Limite el número de entradas de los encabezados reenviados a 2.
  • Agregue una dirección de proxy conocida de 127.0.10.1.
  • Cambie el nombre del encabezado reenviado del valor predeterminado X-Forwarded-For a X-Forwarded-For-My-Custom-Header-Name.
services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardLimit = 2;
    options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
    options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
Opción Descripción
AllowedHosts Restringe los hosts por el encabezado X-Forwarded-Host a los valores proporcionados.
  • Los valores se comparan mediante ordinal-ignore-case.
  • Se deben excluir los números de puerto.
  • Si la lista está vacía, se permiten todos los hosts.
  • Un carácter comodín de nivel superior * permite que todos los hosts que no están vacíos.
  • Se permiten caracteres comodín de subdominio, pero no coinciden con el dominio raíz. Por ejemplo, *.contoso.com coincide con el subdominio foo.contoso.com pero no con el dominio raíz contoso.com.
  • Se permiten nombres de host Unicode, pero se convierten en Punycode para buscar la coincidencia.
  • Las direcciones IPv6 deben incluir corchetes de enlace y estar en formato convencional (por ejemplo, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Las direcciones IPv6 no usan mayúsculas y minúsculas de forma especial para buscar la igualdad lógica entre diferentes formatos, y no se realiza ninguna canonización.
  • Si no se restringen los hosts permitidos, un ciberdelincuente podría suplantar los vínculos generados por el servicio.
El valor predeterminado es un IList<string> vacío.
ForwardedHeaders Identifica qué reenviadores se deben procesar. Consulte ForwardedHeaders Enum para obtener la lista de campos que se aplican. Los valores típicos que se asignan a esta propiedad son ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

El valor predeterminado es ForwardedHeaders.None.
ForwardedForHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedForHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-For sino algún otro para reenviar la información.

El valor predeterminado es X-Forwarded-For.
ForwardedHostHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedHostHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-Host sino algún otro para reenviar la información.

De manera predeterminada, es X-Forwarded-Host.
ForwardedProtoHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedProtoHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-Proto sino algún otro para reenviar la información.

El valor predeterminado es X-Forwarded-Proto.
ForwardedPrefixHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XForwardedPrefixHeaderName. Esta opción se usa cuando el reenviador o proxy no emplea el encabezado X-Forwarded-Prefix sino algún otro para reenviar la información.

El valor predeterminado es X-Forwarded-Prefix.
ForwardLimit Limita el número de entradas en los encabezados que se procesan. Establézcalo en null para deshabilitar el límite, pero esto solo se debe realizar si están configurados KnownProxies o KnownNetworks. Establecer un valor que no sea null es una medida de precaución (no una garantía) para protegerse contra los proxies mal configurados y las peticiones malintencionadas que llegan desde los canales laterales de la red.

El middleware de encabezados reenviados procesa los encabezados en orden inverso, de derecha a izquierda. Si se usa el valor predeterminado (1), solo se procesa el valor más a la derecha de los encabezados, a menos que se aumente el valor de ForwardLimit.

De manera predeterminada, es 1.
KnownNetworks Intervalos de direcciones de redes conocidas de los que se aceptan encabezados reenviados. Proporcione intervalos de direcciones IP mediante la notación de Enrutamiento de interdominios sin clases (CIDR).

Si el servidor usa sockets en modo dual, las direcciones IPv4 se suministran en formato IPv6 (por ejemplo, 10.0.0.1 en IPv4 se representa en IPv6 como ::ffff:10.0.0.1). Consulte IPAddress.MapToIPv6. Para determinar si este formato es necesario, examine HttpContext.Connection.RemoteIpAddress.

El valor predeterminado es un IList<IPNetwork> que contiene una única entrada para new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Direcciones de servidores proxy conocidos de los que se aceptan encabezados reenviados. Use KnownProxies para especificar las coincidencias exactas de direcciones IP.

Si el servidor usa sockets en modo dual, las direcciones IPv4 se suministran en formato IPv6 (por ejemplo, 10.0.0.1 en IPv4 se representa en IPv6 como ::ffff:10.0.0.1). Consulte IPAddress.MapToIPv6. Para determinar si este formato es necesario, examine HttpContext.Connection.RemoteIpAddress.

El valor predeterminado es un IList<IPAddress> que contiene una única entrada para IPAddress.IPv6Loopback.
OriginalForHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

De manera predeterminada, es X-Original-For.
OriginalHostHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

De manera predeterminada, es X-Original-Host.
OriginalProtoHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalProtoHeaderName.

El valor predeterminado es X-Original-Proto.
OriginalPrefixHeaderName Use el encabezado especificado por esta propiedad en lugar del especificado por ForwardedHeadersDefaults.XOriginalPrefixHeaderName.

El valor predeterminado es X-Original-Prefix.
RequireHeaderSymmetry Requiere que el número de valores de encabezado esté sincronizado entre los valores ForwardedHeadersOptions.ForwardedHeaders que se van a procesar.

El valor predeterminado en ASP.NET Core 1.x es true. El valor predeterminado en ASP.NET Core 2.0 o posterior es false.

Escenarios y casos de uso

Cuando no es posible agregar encabezados reenviados y todas las solicitudes son seguras

En algunos casos, puede que no sea posible agregar encabezados reenviados a las solicitudes redirigidas mediante proxy a la aplicación. Si el proxy está forzando a que todas las solicitudes externas públicas sean HTTPS, el esquema se puede establecer manualmente en Startup.Configure antes de usar cualquier tipo de middleware:

app.Use((context, next) =>
{
    context.Request.Scheme = "https";
    return next();
});

Este código puede deshabilitarse con una variable de entorno u otro valor de configuración en un entorno de desarrollo o ensayo.

Tratar con la ruta de acceso base y los servidores proxy que cambian la ruta de acceso de la solicitud

Algunos servidores proxy pasan la ruta de acceso sin cambios pero con una ruta de acceso base de aplicación que se debe quitar para que el enrutamiento funcione correctamente. El middleware UsePathBaseExtensions.UsePathBase divide la ruta de acceso en HttpRequest.Path y la ruta de acceso base de aplicación en HttpRequest.PathBase.

Si /foo es la ruta de acceso base de aplicación para una ruta de acceso de proxy que se pasa como /foo/api/1, el middleware establece Request.PathBase en /foo y Request.Path en /api/1 con el siguiente comando:

app.UsePathBase("/foo");

La ruta de acceso base y la ruta de acceso original se vuelven a aplicar cuando se llama de nuevo al middleware en orden inverso. Para más información sobre el procesamiento de pedidos de middleware, consulte Middleware de ASP.NET Core.

Si el proxy recorta la ruta de acceso (por ejemplo, el reenvío /foo/api/1 a /api/1), corrija los redireccionamientos y los vínculos mediante el establecimiento de la propiedad /foo/api/1 de la solicitud:

app.Use((context, next) =>
{
    context.Request.PathBase = new PathString("/foo");
    return next();
});

Si el proxy va a agregar datos de ruta de acceso, descarte parte de esta ruta para corregir los redireccionamientos y los vínculos; para ello, use StartsWithSegments y asígnelo a la propiedad Path:

app.Use((context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
    {
        context.Request.Path = remainder;
    }

    return next();
});

Configuración de un proxy que usa otros nombres de encabezado

Si el proxy no usa los encabezados denominados X-Forwarded-For y X-Forwarded-Proto para reenviar el puerto o la dirección de proxy y originar información de esquema, establezca las opciones ForwardedForHeaderName y ForwardedProtoHeaderName de modo que coincidan con los nombres de encabezado empleados por el proxy:

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedForHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-For_Header";
    options.ForwardedProtoHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-Proto_Header";
});

Reenvío del esquema para servidores proxy inversos Linux y que no son de IIS

Las aplicaciones que llaman a los métodos UseHttpsRedirection y UseHsts incluyen un sitio en un bucle infinito si se implementan en una instancia de Azure App Service de Linux, una máquina virtual Linux de Azure, o bien detrás de cualquier otro servidor proxy inverso, además de IIS. El servidor proxy inverso termina TLS y Kestrel no es consciente del esquema de solicitud correcto. En esta configuración también se produce un error de OAuth y OIDC, ya que generan redirecciones incorrectas. UseIISIntegration agrega y configura middleware de encabezados reenviados cuando se ejecuta detrás de IIS, pero no hay ninguna configuración automática coincidente para Linux (integración de Apache o Nginx).

Para reenviar el esquema desde el servidor proxy en escenarios que no sean de IIS, agregue y configure Middleware de encabezados reenviados. En Startup.ConfigureServices, use el código siguiente:

// using Microsoft.AspNetCore.HttpOverrides;

if (string.Equals(
    Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
    "true", StringComparison.OrdinalIgnoreCase))
{
    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
            ForwardedHeaders.XForwardedProto;
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit
        // configuration.
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });
}

Reenvío de certificados

Azure

Para configurar Azure App Service para el reenvío de certificados, consulte Configuración de la autenticación mutua de TLS en Azure App Service. La guía siguiente se aplica a la configuración de la aplicación de ASP.NET Core.

En Startup.Configure, agregue el código siguiente antes de llamar a app.UseAuthentication();:

app.UseCertificateForwarding();

Configure el middleware de reenvío de certificados para especificar el nombre de encabezado que Azure usa. En Startup.ConfigureServices, agregue el código siguiente para configurar el encabezado desde el que el middleware crea un certificado:

services.AddCertificateForwarding(options =>
    options.CertificateHeader = "X-ARR-ClientCert");

Otros servidores proxy web

Si se usa un proxy que no es IIS ni Enrutamiento de solicitud de aplicaciones de Azure App Service, configure el proxy para reenviar el certificado que recibió en un encabezado HTTP. En Startup.Configure, agregue el código siguiente antes de llamar a app.UseAuthentication();:

app.UseCertificateForwarding();

Configure el middleware de reenvío de certificados para especificar el nombre del encabezado. En Startup.ConfigureServices, agregue el código siguiente para configurar el encabezado desde el que el middleware crea un certificado:

services.AddCertificateForwarding(options =>
    options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");

Si el proxy no codifica en Base64 el certificado (como ocurre con Nginx), establezca la opción HeaderConverter. Considere el ejemplo siguiente de Startup.ConfigureServices:

services.AddCertificateForwarding(options =>
{
    options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
    options.HeaderConverter = (headerValue) =>
    {
        var clientCertificate =
           /* some conversion logic to create an X509Certificate2 */
        return clientCertificate;
    }
});

Solucionar problemas

Cuando no se reenvíen los encabezados como estaba previsto, habilite el registro. Si los registros no proporcionan suficiente información para solucionar el problema, enumere los encabezados de solicitud recibidos por el servidor. Use middleware insertado para escribir encabezados de solicitud en la respuesta de una aplicación o para registrar los encabezados.

Para escribir los encabezados en la respuesta de la aplicación, coloque el siguiente middleware insertado terminal inmediatamente después de la llamada a UseForwardedHeaders en Startup.Configure:

app.Run(async (context) =>
{
    context.Response.ContentType = "text/plain";

    // Request method, scheme, and path
    await context.Response.WriteAsync(
        $"Request Method: {context.Request.Method}{Environment.NewLine}");
    await context.Response.WriteAsync(
        $"Request Scheme: {context.Request.Scheme}{Environment.NewLine}");
    await context.Response.WriteAsync(
        $"Request Path: {context.Request.Path}{Environment.NewLine}");

    // Headers
    await context.Response.WriteAsync($"Request Headers:{Environment.NewLine}");

    foreach (var header in context.Request.Headers)
    {
        await context.Response.WriteAsync($"{header.Key}: " +
            $"{header.Value}{Environment.NewLine}");
    }

    await context.Response.WriteAsync(Environment.NewLine);

    // Connection: RemoteIp
    await context.Response.WriteAsync(
        $"Request RemoteIp: {context.Connection.RemoteIpAddress}");
});

Puede escribir en registros en lugar de en el cuerpo de respuesta. Así el sitio funcionará con normalidad durante la depuración.

Para ello, siga estos pasos:

  • Inserte ILogger<Startup> en la clase Startup como se describe en ILogger<Startup>.
  • Coloque el siguiente software intermedio insertado inmediatamente después de la llamada a UseForwardedHeaders en Startup.Configure.
app.Use(async (context, next) =>
{
    // Request method, scheme, path, and base path
    _logger.LogDebug("Request Method: {Method}", context.Request.Method);
    _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
    _logger.LogDebug("Request Path: {Path}", context.Request.Path);
    _logger.LogDebug("Request Path Base: {PathBase}", context.Request.PathBase);

    // Headers
    foreach (var header in context.Request.Headers)
    {
        _logger.LogDebug("Header: {Key}: {Value}", header.Key, header.Value);
    }

    // Connection: RemoteIp
    _logger.LogDebug("Request RemoteIp: {RemoteIpAddress}",
        context.Connection.RemoteIpAddress);

    await next();
});

Si se procesa, los valores X-Forwarded-{For|Proto|Host|Prefix} se trasladan a X-Original-{For|Proto|Host|Prefix}. Si hay varios valores en un encabezado determinado, el middleware de encabezados reenviados procesa los encabezados en orden inverso, de derecha a izquierda. El valor predeterminado de ForwardLimit es 1 (uno), por lo que solo el valor más a la derecha de los encabezados se procesa, a menos que se aumente el valor de ForwardLimit.

La dirección IP remota original de la solicitud debe coincidir con una entrada de las listas KnownProxies o KnownNetworks antes de procesar los encabezados reenviados. Esto limita la suplantación de encabezados al no aceptarse reenviadores de servidores proxy que no son de confianza. Cuando se detecta un servidor proxy desconocido, el registro indica la dirección de dicho proxy:

September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321

En el ejemplo anterior, 10.0.0.100 es un servidor proxy. Si se trata de un servidor proxy de confianza, agregue la dirección IP del servidor a KnownProxies o agregue una red de confianza a KnownNetworks en Startup.ConfigureServices. Para más información, vea la sección Opciones del Middleware de encabezados reenviados.

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

Importante

Admita solo las redes y los servidores proxy de confianza para reenviar encabezados. De lo contrario, se pueden producir ataques de suplantación de IP.

Recursos adicionales