Compartilhar via


Configurar o ASP.NET Core para trabalhar com servidores proxy e balanceadores de carga

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Por Chris Ross

Na configuração recomendada para o ASP.NET Core, o aplicativo é hospedado usando o Módulo do ASP.NET Core para IIS, Nginx ou Apache. Servidores proxy, balanceadores de carga e outros dispositivos de rede geralmente ocultam informações sobre a solicitação antes de ela alcançar o aplicativo:

  • Quando solicitações HTTPS são passadas por proxy por HTTP, o esquema original (HTTPS) é perdido e deve ser encaminhado em um cabeçalho.
  • Devido a um aplicativo receber uma solicitação do proxy e não de sua origem verdadeira na Internet ou rede corporativa, o endereço IP do cliente originador também deve ser encaminhado em um cabeçalho.

Essas informações podem ser importantes no processamento de solicitações, por exemplo, em redirecionamentos, autenticação, geração de link, avaliação de política e localização geográfica do cliente.

Os aplicativos destinados a serem executados no farm da Web devem ler Host ASP.NET Core em um farm da Web.

Cabeçalhos encaminhados

Por convenção, os proxies encaminham informações em cabeçalhos HTTP.

parâmetro Descrição
X-Forwarded-For (XFF) Contém informações sobre o cliente que iniciou a solicitação e os proxies subsequentes em uma cadeia de proxies. Esse parâmetro pode conter endereços IP e, opcionalmente, os números de porta. Em uma cadeia de servidores proxy, o primeiro parâmetro indica o cliente em que a solicitação foi feita pela primeira vez. Depois, vêm os identificadores de proxy subsequentes. O último proxy na cadeia não está na lista de parâmetros. O endereço IP do último proxy (e opcionalmente um número da porta) estão disponíveis como o endereço IP remoto na camada de transporte.
X-Forwarded-Proto (XFP) O valor do esquema de origem: HTTP ou HTTPS. O valor também pode ser uma lista de esquemas se a solicitação percorreu vários proxies.
X-Forwarded-Host (XFH) O valor original do campo de cabeçalho do host. Normalmente, os proxies não modificam o cabeçalho do host. Veja Microsoft Security Advisory CVE-2018-0787 para obter informações sobre uma vulnerabilidade de elevação de privilégios que afeta os sistemas em que o proxy não valida ou restringe cabeçalhos de Host a valores válidos conhecidos.
X-Forwarded-Prefix O caminho base original solicitado pelo cliente. Esse cabeçalho pode ser útil para aplicativos gerarem corretamente URLs, redirecionamentos ou links de volta para o cliente.

O middleware de cabeçalhos encaminhados ForwardedHeadersMiddleware lê esses cabeçalhos e preenche os campos associados em HttpContext.

As atualizações de middleware:

Saiba mais neste tópico do GitHub.

As configurações padrão de middleware de cabeçalhos encaminhados podem ser definidas. Para as configurações padrão:

  • Há apenas um proxy entre o aplicativo e a origem das solicitações.
  • Somente os endereços de loopback são configurados para proxies conhecidos e redes conhecidas.
  • Os cabeçalhos encaminhados são nomeados X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host e X-Forwarded-Prefix.
  • O valor ForwardedHeaders é ForwardedHeaders.None, os encaminhadores desejados devem ser definidos aqui para habilitar o middleware.

Nem todos os dispositivos de rede adicionam os cabeçalhos X-Forwarded-For e X-Forwarded-Proto sem configuração adicional. Consulte as diretrizes do fabricante do dispositivo se as solicitações de proxies não contiverem esses cabeçalhos quando atingirem o aplicativo. Se o dispositivo usar nomes de cabeçalho diferente de X-Forwarded-For e X-Forwarded-Proto, defina as opções ForwardedForHeaderName e ForwardedProtoHeaderName para corresponder aos nomes de cabeçalho usados pelo dispositivo. Para obter mais informações, consulte Forwarded Headers Middleware options (Opções de middleware de cabeçalhos encaminhados) e Configuration for a proxy that uses different header names (Configuração de um proxy que usa diferentes nomes de cabeçalho).

O IIS/IIS Express e o Módulo do ASP.NET Core

O Middleware de Cabeçalhos Encaminhados é habilitado por padrão pelo Middleware de integração do IIS quando o aplicativo é hospedado fora do processo atrás do IIS e do Módulo do ASP.NET Core para IIS. O middleware de cabeçalhos encaminhados é ativado para ser executado primeiro no pipeline de middleware, com uma configuração restrita específica para o Módulo do ASP.NET Core. A configuração restrita é devido a preocupações de confiança com cabeçalhos encaminhados, por exemplo, falsificação de IP. O middleware está configurado para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto e é restrito a um proxy de localhost único. Se configuração adicional for necessária, veja as Opções de middleware de cabeçalhos encaminhados.

Outros cenários de servidor proxy e balanceador de carga

Além de usar a Integração do IIS quando hospedar fora do processo, o Middleware de cabeçalhos encaminhados não é habilitado por padrão. O middleware de cabeçalhos encaminhados deve ser habilitado para um aplicativo para processar cabeçalhos encaminhados com UseForwardedHeaders. Após a habilitação do middleware, se nenhum ForwardedHeadersOptions for especificado para o middleware, o ForwardedHeadersOptions.ForwardedHeaders padrão será ForwardedHeaders.None.

Configure o middleware com ForwardedHeadersOptions para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto.

Ordem de Middleware de Cabeçalhos Encaminhados

Middlewares de Cabeçalhos Encaminhados devem ser executados antes de outros middlewares. Essa ordenação garantirá que o middleware conte com informações de cabeçalhos encaminhadas que podem consumir os valores de cabeçalho para processamento. O middleware de cabeçalhos encaminhados pode ser executado após diagnóstico e tratamento de erros, mas ele deve ser executado antes de chamar 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, chame UseForwardedHeaders antes do 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();

Observação

Se nenhum ForwardedHeadersOptions for especificado ou aplicado diretamente no método de extensão com UseForwardedHeaders, os cabeçalhos padrão para encaminhar serão ForwardedHeaders.None. A propriedade ForwardedHeaders deve ser configurada com os cabeçalhos para encaminhar.

Configuração de Nginx

Para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto, confira Host ASP.NET Core no Linux com Nginx. Para obter mais informações, veja NGINX: usando o cabeçalho encaminhado.

Configuração do Apache

X-Forwarded-For é adicionado automaticamente. Para obter mais informações, confira mod_proxy do módulo do Apache: cabeçalhos de solicitação de proxy reverso.

Opções de middleware de cabeçalhos encaminhados

ForwardedHeadersOptions controla o comportamento do middleware de cabeçalhos encaminhados. O seguinte exemplo altera os valores padrão:

  • Limita o número de entradas nos cabeçalhos encaminhados a 2.
  • Adiciona um endereço de proxy conhecido de 127.0.10.1.
  • Altera o nome do cabeçalho encaminhado do padrão X-Forwarded-For para 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();
Opção Descrição
AllowedHosts Restringe os hosts com o cabeçalho X-Forwarded-Host para os valores fornecidos.
  • Os valores são comparados usando ordinal-ignore-case.
  • Os número de porta devem ser excluídos.
  • Se a lista estiver vazia, todos os hosts serão permitidos.
  • Um curinga de nível superior * permite todos os hosts não vazios.
  • Curingas de subdomínio são permitidos, mas não correspondem ao domínio raiz. Por exemplo, *.contoso.com corresponde o subdomínio foo.contoso.com, mas não ao domínio raiz contoso.com.
  • Nomes do host Unicode são permitidos, mas são convertidos em Punycode para correspondência.
  • Endereços IPv6 devem incluir colchetes delimitadores e estar no formato convencional (por exemplo, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Endereços IPv6 não têm caso especial para verificar se há igualdade lógica entre formatos diferentes, e nenhuma canonicalização é executada.
  • Falha ao restringir os hosts permitidos pode permitir que um invasor cibernético falsifique links gerados pelo serviço.
O valor padrão é um IList<string> vazio.
ForwardedForHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedForHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-For, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-For.
ForwardedHeaders Identifica quais encaminhadores devem ser processados. Veja o ForwardedHeaders Enum para a lista de campos aplicáveis. Os valores típicos atribuídos a essa propriedade são ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

O valor padrão é ForwardedHeaders.None.
ForwardedHostHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedHostHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-Host, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-Host.
ForwardedProtoHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedProtoHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-Proto, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-Proto.
ForwardLimit Limita o número de entradas nos cabeçalhos que são processados. Defina para null para desabilitar o limite, mas isso só deve ser feito se KnownProxies ou KnownNetworks estão configurados. A definição de um valor não null é feita por precaução (o que não implica em uma garantia), para proteção contra proxies mal configurados e solicitações mal-intencionadas que chegam de canais secundários na rede.

O middleware de cabeçalhos encaminhados processa cabeçalhos na ordem inversa, da direita para esquerda. Se o valor padrão for usado (1), apenas o valor mais à direita dos cabeçalhos será processado, a menos que o valor de ForwardLimit seja aumentado.

O padrão é 1.
KnownNetworks Intervalos de endereços de redes conhecidas dos quais aceitar cabeçalhos encaminhados. Forneça os intervalos de IP usando notação de CIDR (Roteamento entre Domínios sem Classificação).

O servidor usa soquetes de modo duplo e os endereços IPv4 são fornecidos em um formato IPv6 (por exemplo, 10.0.0.1 no formato IPv4 representado no formato IPv6 como ::ffff:10.0.0.1). Confira IPAddress.MapToIPv6. Para determinar se este formato é obrigatório, veja HttpContext.Connection.RemoteIpAddress.

O padrão é uma IList<IPNetwork> que contém uma única entrada para new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Endereços de proxies conhecidos dos quais aceitar cabeçalhos encaminhados. Use KnownProxies especificar correspondências exatas de endereço IP.

O servidor usa soquetes de modo duplo e os endereços IPv4 são fornecidos em um formato IPv6 (por exemplo, 10.0.0.1 no formato IPv4 representado no formato IPv6 como ::ffff:10.0.0.1). Confira IPAddress.MapToIPv6. Para determinar se este formato é obrigatório, veja HttpContext.Connection.RemoteIpAddress.

O padrão é uma IList<IPAddress> que contém uma única entrada para IPAddress.IPv6Loopback.
OriginalForHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

O padrão é X-Original-For.
OriginalHostHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalHostHeaderName.

O padrão é X-Original-Host.
OriginalProtoHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalProtoHeaderName.

O padrão é X-Original-Proto.
RequireHeaderSymmetry Exigem o número de valores de cabeçalho a serem sincronizados entre os ForwardedHeadersOptions.ForwardedHeaders sendo processados.

O padrão no ASP.NET Core 1.x é true. O padrão no ASP.NET Core 2.0 ou posterior é false.

Cenários e casos de uso

Quando não é possível adicionar cabeçalhos encaminhados e todas as solicitações são seguras

Em alguns casos, pode não ser possível adicionar cabeçalhos encaminhados para as solicitações passadas por proxy ao aplicativo. Se o proxy está impondo que todas as solicitações externas públicas sejam HTTPS, o esquema pode ser definido manualmente antes de usar qualquer 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();

Esse código pode ser desabilitado com uma variável de ambiente ou outra definição de configuração em um ambiente de preparo ou de desenvolvimento:

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();

Trabalhar com o caminho base e proxies que alteram o caminho da solicitação

Alguns proxies passam o caminho intacto, mas com um caminho base de aplicativo que deve ser removido para que o roteamento funcione corretamente. O middleware de UsePathBaseExtensions.UsePathBase divide o caminho em HttpRequest.Path e o caminho base do aplicativo em HttpRequest.PathBase.

Se /foo é o caminho base do aplicativo para um caminho de proxy passado como /foo/api/1, o middleware define Request.PathBase para /foo e Request.Path para /api/1 com o seguinte comando:

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

Observação

Ao usar WebApplication (consulte Migrar do ASP.NET Core 5.0 para o 6.0), app.UseRouting precisa ser chamado após UsePathBase para que o middleware de roteamento possa observar o caminho modificado antes de fazer a correspondência entre as rotas. Caso contrário, a correspondência das rotas é feita antes que o caminho seja reescrito por UsePathBase, conforme descrito nos artigos Ordenação de middleware e Roteamento.

O caminho original e o caminho base são reaplicados quando o middleware é chamado novamente na ordem inversa. Para obter mais informações sobre o processamento de ordem de middleware, veja Middleware do ASP.NET Core.

Se o proxy cortar o caminho (por exemplo, encaminhando /foo/api/1 para /api/1), corrija redirecionamentos e links definindo a propriedade PathBase da solicitação:

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

Se o proxy estiver adicionando dados de caminho, descarte a parte do caminho para corrigir os redirecionamentos e links usando StartsWithSegments e atribuindo à propriedade Path:

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

    return next(context);
});

Configuração de um proxy que usa diferentes nomes de cabeçalho

Se o proxy não usar cabeçalhos nomeados X-Forwarded-For e X-Forwarded-Proto para encaminhar a porta/endereço do proxy e as informações de origem do esquema, defina as opções ForwardedForHeaderName e ForwardedProtoHeaderName para corresponder aos nomes de cabeçalho usados pelo 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();

Encaminhar o esquema para proxies reversos não IIS e Linux

Os aplicativos que chamam UseHttpsRedirection e UseHsts colocam um site em um loop infinito se implantado em um Serviço de Aplicativo do Linux do Azure, VM (máquina virtual) do Azure no Linux ou atrás de outro proxy reverso além do IIS. O TLS é encerrado pelo proxy inverso e o Kestrel não é informado do esquema de solicitação correto. OAuth e OIDC também falham nessa configuração, pois geram redirecionamentos incorretos. UseIISIntegration adiciona e configura o Middleware de Cabeçalhos Encaminhados quando executado atrás do IIS, mas não há nenhuma configuração automática correspondente para Linux (integração do Apache ou do Nginx).

Para encaminhar o esquema do proxy em cenários não de IIS, habilite o Middleware de Cabeçalhos Encaminhados definindo ASPNETCORE_FORWARDEDHEADERS_ENABLED como true. Aviso: esse sinalizador usa configurações projetadas para ambientes de nuvem e não permite recursos como KnownProxies option para restringir quais encaminhadores de IPs são aceitos.

Encaminhamento de certificado

Azure

Para configurar o Serviço de Aplicativo do Azure para encaminhamento de certificado, confira Configurar a autenticação mútua do TLS para o Serviço de Aplicativo do Azure. As diretrizes a seguir referem-se à configuração do aplicativo 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();

Outros proxies da Web

Se um proxy que não seja IIS ou ARR (Application Request Routing) do Serviço de Aplicativo do Azure for usado, configure o proxy para encaminhar o certificado que ele recebeu em um cabeçalho 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();

Se o proxy não estiver codificando o certificado base64, como é o caso do Nginx, defina a opção HeaderConverter. Considere o seguinte exemplo:

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();

Solucionar problemas

Quando os cabeçalhos não são encaminhados conforme o esperado, habilite o registro em log no nível de debug e o registro em log de solicitações HTTP. UseHttpLogging deve ser chamado após 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();

Quando houver vários valores em um determinado cabeçalho, o middleware de cabeçalhos encaminhados os processará na ordem inversa, da direita para esquerda. O padrão ForwardLimit é ForwardLimit (um), portanto, apenas o valor mais à direita dos cabeçalhos será processado, a menos que o valor de 1 seja aumentado.

O IP de remoto original da solicitação precisa corresponder a uma entrada nas listas KnownProxies ou KnownNetworks antes dos cabeçalhos encaminhados serem processados. Isso limita a falsificação de cabeçalho por não aceitar encaminhadores de proxies não confiáveis. Quando um proxy desconhecido é detectado, o registro em log indica o endereço dele:

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

No exemplo anterior, 10.0.0.100 é um servidor proxy. Se o servidor for um proxy confiável, adicione o endereço IP do servidor a KnownProxies ou adicione uma rede confiável a KnownNetworks. Para obter mais informações, consulte a seção Opções de middleware de cabeçalhos encaminhados.

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 exibir os logs, adicione "Microsoft.AspNetCore.HttpLogging": "Information" ao arquivo appsettings.Development.json:

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

Importante

Permitir que somente proxies e redes confiáveis encaminhem os cabeçalhos. Caso contrário, podem ocorrer ataques de falsificação de IP.

Recursos adicionais

Na configuração recomendada para o ASP.NET Core, o aplicativo é hospedado usando IIS/Módulo do ASP.NET Core, Nginx ou Apache. Servidores proxy, balanceadores de carga e outros dispositivos de rede geralmente ocultam informações sobre a solicitação antes de ela alcançar o aplicativo:

  • Quando solicitações HTTPS são passadas por proxy por HTTP, o esquema original (HTTPS) é perdido e deve ser encaminhado em um cabeçalho.
  • Devido a um aplicativo receber uma solicitação do proxy e não de sua origem verdadeira na Internet ou rede corporativa, o endereço IP do cliente originador também deve ser encaminhado em um cabeçalho.

Essas informações podem ser importantes no processamento de solicitações, por exemplo, em redirecionamentos, autenticação, geração de link, avaliação de política e localização geográfica do cliente.

Cabeçalhos encaminhados

Por convenção, os proxies encaminham informações em cabeçalhos HTTP.

parâmetro Descrição
X-Forwarded-For Contém informações sobre o cliente que iniciou a solicitação e os proxies subsequentes em uma cadeia de proxies. Esse parâmetro pode conter endereços IP (e, opcionalmente, os números de porta). Em uma cadeia de servidores proxy, o primeiro parâmetro indica o cliente em que a solicitação foi feita pela primeira vez. Depois, vêm os identificadores de proxy subsequentes. O último proxy na cadeia não está na lista de parâmetros. O endereço IP do último proxy (e opcionalmente um número da porta) estão disponíveis como o endereço IP remoto na camada de transporte.
X-Forwarded-Proto O valor do esquema de origem (HTTP/HTTPS). O valor também pode ser uma lista de esquemas se a solicitação percorreu vários proxies.
X-Forwarded-Host O valor original do campo de cabeçalho do host. Normalmente, os proxies não modificam o cabeçalho do host. Veja Microsoft Security Advisory CVE-2018-0787 para obter informações sobre uma vulnerabilidade de elevação de privilégios que afeta os sistemas em que o proxy não valida ou restringe cabeçalhos de Host a valores válidos conhecidos.

O middleware de cabeçalhos encaminhados (ForwardedHeadersMiddleware) lê esses cabeçalhos e preenche os campos associados em HttpContext.

As atualizações de middleware:

Saiba mais neste tópico do GitHub.

As configurações padrão de middleware de cabeçalhos encaminhados podem ser definidas. Para as configurações padrão:

  • Há apenas um proxy entre o aplicativo e a origem das solicitações.
  • Somente os endereços de loopback são configurados para proxies conhecidos e redes conhecidas.
  • Os cabeçalhos encaminhados são nomeados X-Forwarded-For e X-Forwarded-Proto.
  • O valor ForwardedHeaders é ForwardedHeaders.None, os encaminhadores desejados devem ser definidos aqui para habilitar o middleware.

Nem todos os dispositivos de rede adicionam os cabeçalhos X-Forwarded-For e X-Forwarded-Proto sem configuração adicional. Consulte as diretrizes do fabricante do dispositivo se as solicitações de proxies não contiverem esses cabeçalhos quando atingirem o aplicativo. Se o dispositivo usar nomes de cabeçalho diferente de X-Forwarded-For e X-Forwarded-Proto, defina as opções ForwardedForHeaderName e ForwardedProtoHeaderName para corresponder aos nomes de cabeçalho usados pelo dispositivo. Para obter mais informações, consulte Forwarded Headers Middleware options (Opções de middleware de cabeçalhos encaminhados) e Configuration for a proxy that uses different header names (Configuração de um proxy que usa diferentes nomes de cabeçalho).

O IIS/IIS Express e o Módulo do ASP.NET Core

O Middleware de Cabeçalhos Encaminhados é habilitado por padrão pelo Middleware de integração do IIS quando o aplicativo é hospedado fora do processo atrás do IIS e do Módulo do ASP.NET Core. O middleware de cabeçalhos encaminhados é ativado para ser executado primeiro no pipeline de middleware, com uma configuração restrita específica para o Módulo do ASP.NET Core devido a questões de confiança com cabeçalhos encaminhados (por exemplo, falsificação de IP). O middleware está configurado para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto e é restrito a um proxy de localhost único. Se configuração adicional for necessária, veja as Opções de middleware de cabeçalhos encaminhados.

Outros cenários de servidor proxy e balanceador de carga

Além de usar a Integração do IIS quando hospedar fora do processo, o Middleware de cabeçalhos encaminhados não é habilitado por padrão. O middleware de cabeçalhos encaminhados deve ser habilitado para um aplicativo para processar cabeçalhos encaminhados com UseForwardedHeaders. Após a habilitação do middleware, se nenhum ForwardedHeadersOptions for especificado para o middleware, o ForwardedHeadersOptions.ForwardedHeaders padrão será ForwardedHeaders.None.

Configure o middleware com ForwardedHeadersOptions para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto em Startup.ConfigureServices.

Ordem de Middleware de Cabeçalhos Encaminhados

Middlewares de Cabeçalhos Encaminhados devem ser executados antes de outros middlewares. Essa ordenação garantirá que o middleware conte com informações de cabeçalhos encaminhadas que podem consumir os valores de cabeçalho para processamento. O middleware de cabeçalhos encaminhados pode ser executado após diagnóstico e tratamento de erros, mas ele deve ser executado antes de chamar 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, chame UseForwardedHeaders antes do 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?}");
    });
}

Observação

Se nenhum ForwardedHeadersOptions for especificado no Startup.ConfigureServices ou diretamente no método de extensão com UseForwardedHeaders, os cabeçalhos padrão para encaminhar serão ForwardedHeaders.None. A propriedade ForwardedHeaders deve ser configurada com os cabeçalhos para encaminhar.

Configuração de Nginx

Para encaminhar os cabeçalhos X-Forwarded-For e X-Forwarded-Proto, confira Host ASP.NET Core no Linux com Nginx. Para obter mais informações, veja NGINX: usando o cabeçalho encaminhado.

Configuração do Apache

X-Forwarded-For é adicionado automaticamente (veja mod_proxy do módulo do Apache: cabeçalhos de solicitação de proxy reverso).

Opções de middleware de cabeçalhos encaminhados

ForwardedHeadersOptions controla o comportamento do middleware de cabeçalhos encaminhados. O seguinte exemplo altera os valores padrão:

  • Limite o número de entradas nos cabeçalhos encaminhados a 2.
  • Adicione um endereço de proxy conhecido de 127.0.10.1.
  • Altere o nome do cabeçalho encaminhado do padrão X-Forwarded-For para 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";
});
Opção Descrição
AllowedHosts Restringe os hosts com o cabeçalho X-Forwarded-Host para os valores fornecidos.
  • Os valores são comparados usando ordinal-ignore-case.
  • Os número de porta devem ser excluídos.
  • Se a lista estiver vazia, todos os hosts serão permitidos.
  • Um curinga de nível superior * permite todos os hosts não vazios.
  • Curingas de subdomínio são permitidos, mas não correspondem ao domínio raiz. Por exemplo, *.contoso.com corresponde o subdomínio foo.contoso.com, mas não ao domínio raiz contoso.com.
  • Nomes do host Unicode são permitidos, mas são convertidos em Punycode para correspondência.
  • Endereços IPv6 devem incluir colchetes delimitadores e estar no formato convencional (por exemplo, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Endereços IPv6 não têm caso especial para verificar se há igualdade lógica entre formatos diferentes, e nenhuma canonicalização é executada.
  • Falha ao restringir os hosts permitidos pode permitir que um invasor cibernético falsifique links gerados pelo serviço.
O valor padrão é um IList<string> vazio.
ForwardedHeaders Identifica quais encaminhadores devem ser processados. Veja o ForwardedHeaders Enum para a lista de campos aplicáveis. Os valores típicos atribuídos a essa propriedade são ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

O valor padrão é ForwardedHeaders.None.
ForwardedForHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedForHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-For, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-For.
ForwardedHostHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedHostHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-Host, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-Host.
ForwardedProtoHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XForwardedProtoHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-Proto, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-Proto.
ForwardedPrefixHeaderName Use o cabeçalho especificado por essa propriedade em vez do especificado por ForwardedHeadersDefaults.XForwardedPrefixHeaderName. Esta opção é usada quando o proxy/encaminhador não usa o cabeçalho X-Forwarded-Prefix, mas usa algum outro cabeçalho para encaminhar as informações.

O padrão é X-Forwarded-Prefix.
ForwardLimit Limita o número de entradas nos cabeçalhos que são processados. Defina para null para desabilitar o limite, mas isso só deve ser feito se KnownProxies ou KnownNetworks estão configurados. A definição de um valor não null é feita por precaução (o que não implica em uma garantia), para proteção contra proxies mal configurados e solicitações mal-intencionadas que chegam de canais secundários na rede.

O middleware de cabeçalhos encaminhados processa cabeçalhos na ordem inversa, da direita para esquerda. Se o valor padrão for usado (1), apenas o valor mais à direita dos cabeçalhos será processado, a menos que o valor de ForwardLimit seja aumentado.

O padrão é 1.
KnownNetworks Intervalos de endereços de redes conhecidas dos quais aceitar cabeçalhos encaminhados. Forneça os intervalos de IP usando notação de CIDR (Roteamento entre Domínios sem Classificação).

O servidor usa soquetes de modo duplo e os endereços IPv4 são fornecidos em um formato IPv6 (por exemplo, 10.0.0.1 no formato IPv4 representado no formato IPv6 como ::ffff:10.0.0.1). Confira IPAddress.MapToIPv6. Para determinar se este formato é obrigatório, veja HttpContext.Connection.RemoteIpAddress.

O padrão é uma IList<IPNetwork> que contém uma única entrada para new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Endereços de proxies conhecidos dos quais aceitar cabeçalhos encaminhados. Use KnownProxies especificar correspondências exatas de endereço IP.

O servidor usa soquetes de modo duplo e os endereços IPv4 são fornecidos em um formato IPv6 (por exemplo, 10.0.0.1 no formato IPv4 representado no formato IPv6 como ::ffff:10.0.0.1). Confira IPAddress.MapToIPv6. Para determinar se este formato é obrigatório, veja HttpContext.Connection.RemoteIpAddress.

O padrão é uma IList<IPAddress> que contém uma única entrada para IPAddress.IPv6Loopback.
OriginalForHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalForHeaderName.

O padrão é X-Original-For.
OriginalHostHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalHostHeaderName.

O padrão é X-Original-Host.
OriginalProtoHeaderName Use o cabeçalho especificado por essa propriedade, em vez de um especificado por ForwardedHeadersDefaults.XOriginalProtoHeaderName.

O padrão é X-Original-Proto.
OriginalPrefixHeaderName Use o cabeçalho especificado por essa propriedade em vez do especificado por ForwardedHeadersDefaults.XOriginalPrefixHeaderName.

O padrão é X-Original-Prefix.
RequireHeaderSymmetry Exigem o número de valores de cabeçalho a serem sincronizados entre os ForwardedHeadersOptions.ForwardedHeaders sendo processados.

O padrão no ASP.NET Core 1.x é true. O padrão no ASP.NET Core 2.0 ou posterior é false.

Cenários e casos de uso

Quando não é possível adicionar cabeçalhos encaminhados e todas as solicitações são seguras

Em alguns casos, pode não ser possível adicionar cabeçalhos encaminhados para as solicitações passadas por proxy ao aplicativo. Se o proxy está impondo que todas as solicitações externas públicas sejam HTTPS, o esquema pode ser definido manualmente em Startup.Configure antes de usar qualquer tipo de middleware:

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

Esse código pode ser desabilitado com uma variável de ambiente ou outra definição de configuração em um ambiente de preparo ou de desenvolvimento.

Lidar com o caminho base e proxies que alteram o caminho da solicitação

Alguns proxies passam o caminho intacto, mas com um caminho base de aplicativo que deve ser removido para que o roteamento funcione corretamente. O middleware de UsePathBaseExtensions.UsePathBase divide o caminho em HttpRequest.Path e o caminho base do aplicativo em HttpRequest.PathBase.

Se /foo é o caminho base do aplicativo para um caminho de proxy passado como /foo/api/1, o middleware define Request.PathBase para /foo e Request.Path para /api/1 com o seguinte comando:

app.UsePathBase("/foo");

O caminho original e o caminho base são reaplicados quando o middleware é chamado novamente na ordem inversa. Para obter mais informações sobre o processamento de ordem de middleware, veja Middleware do ASP.NET Core.

Se o proxy cortar o caminho (por exemplo, encaminhando /foo/api/1 para /api/1), corrija redirecionamentos e links definindo a propriedade PathBase da solicitação:

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

Se o proxy estiver adicionando dados de caminho, descarte a parte do caminho para corrigir os redirecionamentos e links usando StartsWithSegments e atribuindo à propriedade Path:

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

    return next();
});

Configuração de um proxy que usa diferentes nomes de cabeçalho

Se o proxy não usar cabeçalhos nomeados X-Forwarded-For e X-Forwarded-Proto para encaminhar a porta/endereço do proxy e as informações de origem do esquema, defina as opções ForwardedForHeaderName e ForwardedProtoHeaderName para corresponder aos nomes de cabeçalho usados pelo 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";
});

Encaminhar o esquema para proxies reversos não IIS e Linux

Os aplicativos que chamam UseHttpsRedirection e UseHsts colocam um site em um loop infinito se implantado em um Serviço de Aplicativo do Linux do Azure, VM (máquina virtual) do Azure no Linux ou atrás de outro proxy reverso além do IIS. O TLS é encerrado pelo proxy inverso e o Kestrel não é informado do esquema de solicitação correto. OAuth e OIDC também falham nessa configuração, pois geram redirecionamentos incorretos. UseIISIntegration adiciona e configura o Middleware de Cabeçalhos Encaminhados quando executado atrás do IIS, mas não há nenhuma configuração automática correspondente para Linux (integração do Apache ou do Nginx).

Para encaminhar o esquema do proxy em cenários não de IIS, adicione e configure o Middleware de Cabeçalhos Encaminhados. No Startup.ConfigureServices, use o código a seguir:

// 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();
    });
}

Encaminhamento de certificado

Azure

Para configurar o Serviço de Aplicativo do Azure para encaminhamento de certificado, confira Configurar a autenticação mútua do TLS para o Serviço de Aplicativo do Azure. As diretrizes a seguir referem-se à configuração do aplicativo ASP.NET Core.

Em Startup.Configure, adicione o código a seguir antes da chamada para app.UseAuthentication();:

app.UseCertificateForwarding();

Configure o Middleware de Encaminhamento de Certificado para especificar o nome de cabeçalho que o Azure usa. Em Startup.ConfigureServices, adicione o código a seguir para configurar o cabeçalho do qual o middleware cria um certificado:

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

Outros proxies da Web

Se um proxy que não seja IIS ou ARR (Application Request Routing) do Serviço de Aplicativo do Azure for usado, configure o proxy para encaminhar o certificado que ele recebeu em um cabeçalho HTTP. Em Startup.Configure, adicione o código a seguir antes da chamada para app.UseAuthentication();:

app.UseCertificateForwarding();

Configure o Middleware de Encaminhamento de Certificado para especificar o nome de cabeçalho. Em Startup.ConfigureServices, adicione o código a seguir para configurar o cabeçalho do qual o middleware cria um certificado:

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

Se o proxy não estiver codificando o certificado base64 (como é o caso do Nginx) defina a opção HeaderConverter. Considere o exemplo a seguir em 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

Quando os cabeçalhos não são encaminhados conforme o esperado, habilite registro em log. Se os logs não fornecerem informações suficientes para solucionar o problema, enumere os cabeçalhos de solicitação recebidos pelo servidor. Use middleware embutido para gravar cabeçalhos de solicitação para uma resposta do aplicativo ou para log dos cabeçalhos.

Para gravar os cabeçalhos de resposta do aplicativo, coloque o seguinte middleware terminal embutido imediatamente após a chamada para UseForwardedHeaders em 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}");
});

Você pode gravar em logs em vez de no corpo da resposta. A gravação em logs permite que o site funcione normalmente durante a depuração.

Para gravar em logs em vez de no corpo da resposta:

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();
});

Quando processado, os valores X-Forwarded-{For|Proto|Host|Prefix} são movidos para X-Original-{For|Proto|Host|Prefix}. Quando houver vários valores em um determinado cabeçalho, o middleware de cabeçalhos encaminhados os processará na ordem inversa, da direita para esquerda. O padrão ForwardLimit é ForwardLimit (um), portanto, apenas o valor mais à direita dos cabeçalhos será processado, a menos que o valor de 1 seja aumentado.

O IP de remoto original da solicitação precisa corresponder a uma entrada nas listas KnownProxies ou KnownNetworks antes dos cabeçalhos encaminhados serem processados. Isso limita a falsificação de cabeçalho por não aceitar encaminhadores de proxies não confiáveis. Quando um proxy desconhecido é detectado, o registro em log indica o endereço dele:

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

No exemplo anterior, 10.0.0.100 é um servidor proxy. Se o servidor for um proxy confiável, adicione o endereço IP do servidor a KnownProxies (ou adicione uma rede confiável a KnownNetworks) em Startup.ConfigureServices. Para obter mais informações, consulte a seção Opções de middleware de cabeçalhos encaminhados.

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

Importante

Permitir que somente proxies e redes confiáveis encaminhem os cabeçalhos. Caso contrário, podem ocorrer ataques de falsificação de IP.

Recursos adicionais