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:
HttpContext.Connection.RemoteIpAddress
: establécelo mediante el valor de encabezadoX-Forwarded-For
. Los valores de configuración adicionales afectan a cómo el middleware estableceRemoteIpAddress
. Para más información, consulte la sección Opciones de Middleware de encabezados reenviados. Los valores consumidos se quitan deX-Forwarded-For
y los valores antiguos deHttpContext.Connection.RemoteIpAddress
se conservan enX-Original-For
. Nota: Este proceso puede repetirse varias veces si hay varios valores enX-Forwarded-For/Proto/Host/Prefix
, lo que da lugar a varios valores movidos aX-Original-*
, incluido el valorRemoteIpAddress/Host/Scheme/PathBase
original.HttpContext.Request.Scheme
: establécelo mediante el valor de encabezadoX-Forwarded-Proto
. El valor consumido se quita deX-Forwarded-Proto
y el valor antiguo deHttpContext.Request.Scheme
se conserva enX-Original-Proto
.HttpContext.Request.Host
: establécelo mediante el valor de encabezadoX-Forwarded-Host
. El valor consumido se quita deX-Forwarded-Host
y el valor antiguo deHttpContext.Request.Host
se conserva enX-Original-Host
.HttpContext.Request.PathBase
: establécelo mediante el valor de encabezadoX-Forwarded-Prefix
. El valor consumido se quita deX-Forwarded-Prefix
y el valor antiguo deHttpContext.Request.PathBase
se conserva enX-Original-Prefix
.
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
yX-Forwarded-Prefix
. - El valor de
ForwardedHeaders
esForwardedHeaders.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
aX-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.
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.
- Configure el middleware de reenvío de certificados para especificar el nombre de encabezado que usa Azure. Agregue el código siguiente para configurar el encabezado desde el que el middleware crea un certificado.
- Llame a UseCertificateForwarding antes de la llamada a UseAuthentication.
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.
- Configure el middleware de reenvío de certificados para especificar el nombre del encabezado. Agregue el código siguiente para configurar el encabezado desde el que el middleware crea un certificado.
- Llame a UseCertificateForwarding antes de la llamada a UseAuthentication.
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
- Hospedaje de ASP.NET Core en una granja de servidores web
- Microsoft Security Advisory CVE-2018-0787: ASP.NET Core Elevation Of Privilege Vulnerability (Microsoft Security Advisory CVE-2018-0787: Vulnerabilidad de elevación de privilegios de ASP.NET Core)
- YARP: Yet Another Reverse Proxy
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:
- HttpContext.Connection.RemoteIpAddress: establézcalo mediante el valor de encabezado
X-Forwarded-For
. Los valores de configuración adicionales afectan a cómo el middleware estableceRemoteIpAddress
. Para más información, consulte la sección Opciones de Middleware de encabezados reenviados. Los valores consumidos se quitan deX-Forwarded-For
y los valores antiguos se conservan enX-Original-For
. El mismo patrón se aplica a los demás encabezados,Host
yProto
. - HttpContext.Request.Scheme: establézcalo mediante el valor de encabezado
X-Forwarded-Proto
. - HttpContext.Request.Host: establézcalo mediante el valor de encabezado
X-Forwarded-Host
.
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
yX-Forwarded-Proto
. - El valor de
ForwardedHeaders
esForwardedHeaders.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
aX-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.
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 claseStartup
como se describe enILogger<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
- Hospedaje de ASP.NET Core en una granja de servidores web
- Microsoft Security Advisory CVE-2018-0787: ASP.NET Core Elevation Of Privilege Vulnerability (Microsoft Security Advisory CVE-2018-0787: Vulnerabilidad de elevación de privilegios de ASP.NET Core)
- YARP: Yet Another Reverse Proxy