Configurare ASP.NET Core per l'uso di server proxy e servizi di bilanciamento del carico

Di Chris Ross

Nella configurazione consigliata per ASP.NET Core, l'app viene ospitata usando ASP.NET Core Module (ANCM) per IIS, Nginx o Apache. Server proxy, servizi di bilanciamento del carico e altre appliance di rete spesso nascondono informazioni sulla richiesta prima che questa raggiunga l'app:

  • Quando le richieste HTTPS vengono trasmesse tramite proxy su HTTP, lo schema originale (HTTPS) viene perso e deve essere inoltrato in un'intestazione.
  • Poiché un'app riceve una richiesta dal proxy e non dall'effettiva origine su Internet o nella rete aziendale, anche l'indirizzo IP di origine del client deve essere inoltrato in un'intestazione.

Queste informazioni potrebbero essere importanti per l'elaborazione delle richieste, ad esempio per i reindirizzamenti, l'autenticazione, la generazione di collegamenti, la valutazione dei criteri e la georilevazione dei client.

Le app che devono essere eseguite nella Web farm devono leggere Host ASP.NET Core in una web farm.

Intestazioni inoltrate

Per convenzione, i proxy inoltrano le informazioni nelle intestazioni HTTP.

Intestazione Descrizione
X-Forwarded-For (XFF) Contiene informazioni sul client che ha avviato la richiesta e sui proxy successivi in una catena di proxy. Questo parametro può contenere indirizzi IP e, facoltativamente, numeri di porta. In una catena di server proxy, il primo parametro indica il client in cui è stata eseguita inizialmente la richiesta. Seguono gli identificatori dei proxy successivi. L'ultimo proxy della catena non è incluso nell'elenco dei parametri. L'indirizzo IP dell'ultimo proxy e, facoltativamente, un numero di porta sono disponibili come indirizzo IP remoto a livello di trasporto.
X-Forwarded-Proto (XFP) Valore dello schema di origine, HTTP o HTTPS. Il valore può essere anche un elenco di schemi, se la richiesta ha attraversato più proxy.
X-Forwarded-Host (XFH) Il valore originale del campo dell'intestazione host. I proxy in genere non modificano l'intestazione host. Vedere l'avviso di sicurezza Microsoft CVE-2018-0787 per informazioni su una vulnerabilità di elevazione dei privilegi che interessa i sistemi in cui il proxy non convalida o limita le intestazioni host a valori di riferimento noti.

Il middleware delle intestazioni inoltrate, ForwardedHeadersMiddleware, legge queste intestazioni e compila i campi associati in HttpContext.

Il middleware aggiorna:

Per altre informazioni sull'esempio precedente, vedere questo problema di GitHub.

È possibile configurare le impostazioni predefinite del middleware delle intestazioni inoltrate. Per le impostazioni predefinite:

  • È presente un solo proxy tra l'app e l'origine delle richieste.
  • Sono configurati indirizzi di loopback solo per reti e proxy noti.
  • Le intestazioni inoltrate sono denominate X-Forwarded-For e X-Forwarded-Proto.
  • Il ForwardedHeaders valore è ForwardedHeaders.None, i server d'inoltro desiderati devono essere impostati qui per abilitare il middleware.

Non tutte le appliance di rete aggiungono le intestazioni X-Forwarded-For e X-Forwarded-Proto senza alcuna configurazione aggiuntiva. Se le richieste trasmesse tramite proxy non contengono queste intestazioni quando raggiungono l'app, fare riferimento alle indicazioni del produttore dell'appliance. Se l'appliance usa nomi di intestazione diversi da X-Forwarded-For e X-Forwarded-Proto, impostare le opzioni ForwardedForHeaderName e ForwardedProtoHeaderName in modo che corrispondano ai nomi di intestazione usati dall'appliance. Per altre informazioni, vedere Opzioni del middleware delle intestazioni inoltrate e Configurazione per un proxy che usa nomi di intestazione diversi.

IIS/IIS Express e modulo Core ASP.NET

Il middleware delle intestazioni inoltrate è abilitato per impostazione predefinita dal middleware di integrazione IIS quando l'app è ospitata in modalità out-of-process dietro IIS e la ASP.NET Core Module (ANCM) per IIS. Il middleware delle intestazioni inoltrate viene attivato per l'esecuzione prima nella pipeline middleware con una configurazione limitata specifica del modulo ASP.NET Core. La configurazione con restrizioni è dovuta a problemi di attendibilità con le intestazioni inoltrate, ad esempio lo spoofing IP. Il middleware è configurato per inoltrare le intestazioni X-Forwarded-For e X-Forwarded-Proto ed è limitato a un singolo proxy localhost. Se è richiesta una configurazione aggiuntiva, vedere Opzioni del middleware delle intestazioni inoltrate.

Altri scenari con server proxy e servizi di bilanciamento del carico

All'esterno dell'uso dell'integrazione IIS quando si ospita un middleware out-of-process, il middleware delle intestazioni inoltrate non è abilitato per impostazione predefinita. Il middleware delle intestazioni inoltrate deve essere abilitato per consentire a un'app di inoltrare le intestazioni inoltrate del processo con UseForwardedHeaders. Dopo aver abilitato il middleware, se non sono specificate opzioni ForwardedHeadersOptions per il middleware, le intestazioni ForwardedHeadersOptions.ForwardedHeaders predefinite sono ForwardedHeaders.None.

Configurare il middleware con ForwardedHeadersOptions per inoltrare le X-Forwarded-For intestazioni e X-Forwarded-Proto .

Ordine del middleware delle intestazioni inoltrate

Il middleware delle intestazioni inoltrate deve essere eseguito prima di altri middleware. Questo ordine garantisce che il middleware basato sulle intestazioni inoltrate possa usare i valori di intestazione per l'elaborazione. Il middleware delle intestazioni inoltrate può essere eseguito dopo la diagnostica e la gestione degli errori, ma deve essere eseguito prima di chiamare 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();

In alternativa, chiamare UseForwardedHeaders prima della diagnostica:

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

Se non ForwardedHeadersOptions viene specificato o applicato direttamente al metodo di estensione con UseForwardedHeaders, le intestazioni predefinite da inoltrare sono ForwardedHeaders.None. La proprietà ForwardedHeaders deve essere configurata con le intestazioni da inoltrare.

Configurazione Nginx

Per inoltrare le X-Forwarded-For intestazioni e X-Forwarded-Proto , vedere Host ASP.NET Core in Linux con Nginx. Per altre informazioni, vedere NGINX: Using the Forwarded header (NGINX: Uso dell'intestazione Forwarded).

Configurazione Apache

X-Forwarded-For viene aggiunto automaticamente. Per altre informazioni, vedere Apache Module mod_proxy: Reverse Proxy Request Headers .For more information, see Apache Module mod_proxy: Reverse Proxy Request Headers. Per informazioni su come inoltrare l'intestazione X-Forwarded-Proto , vedere Host ASP.NET Core in Linux con Apache.

Opzioni del middleware delle intestazioni inoltrate

ForwardedHeadersOptions controllare il comportamento del middleware delle intestazioni inoltrate. L'esempio seguente modifica i valori predefiniti:

  • Limita il numero di voci nelle intestazioni inoltrate a 2.
  • Aggiunge un indirizzo proxy noto di 127.0.10.1.
  • Modifica il nome dell'intestazione inoltrata dal valore predefinito X-Forwarded-For a X-Forwarded-For-My-Custom-Header-Name.
using System.Net;

var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

app.UseForwardedHeaders();

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

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

app.UseAuthorization();

app.MapRazorPages();

app.Run();
Opzione Descrizione
AllowedHosts Limita gli host mediante l'intestazione X-Forwarded-Host ai valori specificati.
  • I valori vengono confrontati tramite ordinal-ignore-case.
  • I numeri di porta devono essere esclusi.
  • Se l'elenco è vuoto, sono consentiti tutti gli host.
  • Un carattere jolly di primo livello * consente tutti gli host non vuoti.
  • I caratteri jolly per i sottodomini sono consentiti, ma non corrispondono al dominio radice. Ad esempio, *.contoso.com corrisponde al sottodominio foo.contoso.com, ma non al dominio radice contoso.com.
  • I nomi host Unicode sono consentiti ma vengono convertiti in Punycode per la corrispondenza.
  • Gli indirizzi IPv6 devono includere le parentesi quadre di delimitazione ed essere in formato convenzionale, ad esempio [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]. Per gli indirizzi IPv6 non viene applicata la distinzione tra maiuscole e minuscole per la verifica dell'uguaglianza logica tra i diversi formati e non viene eseguita alcuna canonizzazione.
  • La mancata limitazione degli host consentiti potrebbe permettere a un utente malintenzionato di eseguire lo spoofing dei collegamenti generati dal servizio.
Il valore predefinito è un insieme IList<string> vuoto.
ForwardedForHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedForHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-For ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-For.
ForwardedHeaders Identifica i server d'inoltro che devono essere elaborati. Vedere ForwardedHeaders Enum (Enumerazione ForwardedHeaders) per l'elenco dei campi applicabili. I valori tipici assegnati a questa proprietà sono ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Il valore predefinito è ForwardedHeaders.None.
ForwardedHostHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedHostHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-Host ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-Host.
ForwardedProtoHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedProtoHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-Proto ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-Proto.
ForwardLimit Limita il numero di voci nelle intestazioni elaborate. Impostare su null per disabilitare il limite, ma solo se è configurato KnownProxies o KnownNetworks. L'impostazione di un valore non null è una precauzione (ma non una garanzia) per proteggersi da proxy non configurati correttamente e richieste dannose provenienti da canali laterali in rete.

Il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso da destra a sinistra. Se viene usato il valore predefinito (1), viene elaborato solo il valore più a destra delle intestazioni, a meno che non venga aumentato il valore di ForwardLimit.

Il valore predefinito è 1.
KnownNetworks Intervalli di indirizzi delle reti note da cui accettare le intestazioni inoltrate. Specificare gli intervalli IP usando la notazione CIDR (Classless Interdomain Routing).

Se il server usa socket dual mode, gli indirizzi IPv4 vengono forniti in un formato IPv6 (ad esempio, 10.0.0.1 in IPv4 rappresentato in IPv6 come ::ffff:10.0.0.1). Vedere IPAddress.MapToIPv6. Determinare se questo formato è richiesto esaminando HttpContext.Connection.RemoteIpAddress.

Il valore predefinito è un oggetto IList><IPNetworkcontenente una singola voce per .IPAddress.Loopback
KnownProxies Indirizzi dei proxy noti da cui accettare le intestazioni inoltrate. Usare KnownProxies per specificare le corrispondenze esatte degli indirizzi IP.

Se il server usa socket dual mode, gli indirizzi IPv4 vengono forniti in un formato IPv6 (ad esempio, 10.0.0.1 in IPv4 rappresentato in IPv6 come ::ffff:10.0.0.1). Vedere IPAddress.MapToIPv6. Determinare se questo formato è richiesto esaminando HttpContext.Connection.RemoteIpAddress.

Il valore predefinito è un oggetto IList><IPAddresscontenente una singola voce per .IPAddress.IPv6Loopback
OriginalForHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalForHeaderName.

Il valore predefinito è X-Original-For.
OriginalHostHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalHostHeaderName.

Il valore predefinito è X-Original-Host.
OriginalProtoHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalProtoHeaderName.

Il valore predefinito è X-Original-Proto.
RequireHeaderSymmetry Richiedere il numero di valori di intestazione da sincronizzare tra le intestazioni ForwardedHeadersOptions.ForwardedHeaders in fase di elaborazione.

Il valore predefinito in ASP.NET Core 1.x è true. Il valore predefinito in ASP.NET Core 2.0 o versione successiva è false.

Scenari e casi d'uso

Quando non è possibile aggiungere le intestazioni inoltrate e tutte le richieste sono sicure

In alcuni casi, potrebbe non essere possibile aggiungere le intestazioni inoltrate alle richieste trasmesse tramite proxy all'app. Se il proxy applica che tutte le richieste esterne pubbliche sono HTTPS, lo schema può essere impostato manualmente prima di usare qualsiasi tipo di 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();

Questo codice può essere disabilitato con una variabile di ambiente o un'altra impostazione di configurazione in un ambiente di sviluppo o staging:

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

Usare la base del percorso e i proxy che modificano il percorso della richiesta

Alcuni proxy passano il percorso senza modifiche, ma con un percorso di base dell'app che deve essere rimosso per consentire il corretto funzionamento del routing. Il middleware UsePathBaseExtensions.UsePathBase suddivide il percorso in HttpRequest.Path e il percorso di base dell'app in HttpRequest.PathBase.

Se /foo è il percorso di base dell'app per un percorso proxy passato come /foo/api/1, il middleware imposta Request.PathBase su /foo e Request.Path su /api/1 con il comando seguente:

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

Nota

Quando si usa WebApplication (vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0), app.UseRouting deve essere chiamato dopo UsePathBase in modo che il middleware di routing possa osservare il percorso modificato prima di associare le route. In caso contrario, le route vengono associate prima che il percorso venga riscritto da UsePathBase come descritto negli articoli Ordinamento del middleware e Routing.

Il percorso originale e la base del percorso vengono riapplicati quando il middleware viene chiamato nuovamente in direzione inversa. Per altre informazioni sull'elaborazione degli ordini middleware, vedere ASP.NET Middleware core.

Se il proxy taglia il percorso (ad esempio, inoltrando /foo/api/1 a /api/1), correggere i reindirizzamenti e i collegamenti impostando la proprietà PathBase della richiesta:

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

Se il proxy aggiunge i dati del percorso, eliminare parte del percorso per correggere i reindirizzamenti e i collegamenti usando StartsWithSegments ed eseguendo l'assegnazione alla proprietà Path:

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

    return next(context);
});

Configurazione per un proxy che usa nomi di intestazione diversi

Se il proxy non usa intestazioni denominate X-Forwarded-For e X-Forwarded-Proto per inoltrare l'indirizzo proxy o la porta e le informazioni dello scherma originali, impostare le opzioni ForwardedForHeaderName e ForwardedProtoHeaderName in modo che corrispondano ai nomi di intestazione usati dal 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();

Inoltrare lo schema per Linux e proxy inversi non IIS

Con le app che chiamano UseHttpsRedirection e UseHsts il sito si ritrova in un ciclo infinito se distribuito in un servizio app Linux di Azure, in una macchina virtuale Linux di Azure o dietro eventuali altri proxy inversi diversi da IIS. TLS viene terminato dal proxy inverso e Kestrel non è a conoscenza dello schema di richiesta corretto. Si verificano errori anche per OAuth e OIDC in questa configurazione perché generano reindirizzamenti non corretti. UseIISIntegration aggiunge e configura il middleware delle intestazioni inoltrate in caso di esecuzione dietro IIS, ma non esiste alcuna configurazione automatica corrispondente per Linux (integrazione di Apache o Nginx).

Per inoltrare lo schema dal proxy in scenari non IIS, abilitare il middleware intestazioni inoltrate impostando ASPNETCORE_FORWARDEDHEADERS_ENABLED su true. Avviso: questo flag usa le impostazioni progettate per gli ambienti cloud e non abilita funzionalità come ad KnownProxies option esempio per limitare i server d'inoltro degli indirizzi IP da cui vengono accettati.

Inoltro di certificati

Azure

Per configurare app Azure Servizio per l'inoltro dei certificati, vedere Configurare l'autenticazione reciproca TLS per app Azure Servizio. Le indicazioni seguenti riguardano la configurazione dell'app ASP.NET Core.

  • Configurare il middleware di inoltro certificati per specificare il nome dell'intestazione usato da Azure. Aggiungere il codice seguente per configurare l'intestazione da cui il middleware compila un certificato.
  • Chiamare UseCertificateForwarding prima della chiamata 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();

Altri proxy Web

Se viene usato un proxy che non è IIS o app Azure Service's Application Request Routing (ARR), configurare il proxy per inoltrare il certificato ricevuto in un'intestazione HTTP.

  • Configurare il middleware di inoltro certificati per specificare il nome dell'intestazione. Aggiungere il codice seguente per configurare l'intestazione da cui il middleware compila un certificato.
  • Chiamare UseCertificateForwarding prima della chiamata 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();

Se il proxy non esegue la codifica base64 del certificato, come nel caso di Nginx, impostare l'opzione HeaderConverter . Si consideri l'esempio seguente:

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

Risoluzione dei problemi

Quando le intestazioni non vengono inoltrate come previsto, abilitare la debug registrazione a livello e la registrazione delle richieste HTTP. UseHttpLogging deve essere chiamato dopo 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();

Se sono presenti più valori in una determinata intestazione, il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso da destra a sinistra. Il valore predefinito di ForwardLimit è 1 (uno) e, pertanto, viene elaborato solo il valore più a destra delle intestazioni, a meno che non venga aumentato il valore di ForwardLimit.

L'indirizzo IP remoto originale della richiesta deve corrispondere a una voce negli elenchi KnownProxies o KnownNetworks prima dell'elaborazione delle intestazioni inoltrate. Questo riduce lo spoofing delle intestazioni, non accettando server di inoltro da proxy non attendibili. Quando viene rilevato un proxy sconosciuto, la registrazione indica l'indirizzo del proxy:

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

Nell'esempio precedente, 10.0.0.100 è un server proxy. Se il server è un proxy attendibile, aggiungere l'indirizzo IP del server a KnownProxieso aggiungere una rete attendibile a KnownNetworks. Per altre informazioni, vedere la sezione Opzioni del middleware delle intestazioni inoltrate.

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

Per visualizzare i log, aggiungere "Microsoft.AspNetCore.HttpLogging": "Information" al appsettings.Development.json file:

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

Importante

Consentire solo a reti e proxy attendibili di inoltrare le intestazioni. In caso contrario, possono verificarsi attacchi di spoofing degli indirizzi IP.

Risorse aggiuntive

Nella configurazione consigliata per ASP.NET Core, l'app è ospitata mediante IIS e il modulo ASP.NET Core, Nginx o Apache. Server proxy, servizi di bilanciamento del carico e altre appliance di rete spesso nascondono informazioni sulla richiesta prima che questa raggiunga l'app:

  • Quando le richieste HTTPS vengono trasmesse tramite proxy su HTTP, lo schema originale (HTTPS) viene perso e deve essere inoltrato in un'intestazione.
  • Poiché un'app riceve una richiesta dal proxy e non dall'effettiva origine su Internet o nella rete aziendale, anche l'indirizzo IP di origine del client deve essere inoltrato in un'intestazione.

Queste informazioni potrebbero essere importanti per l'elaborazione delle richieste, ad esempio per i reindirizzamenti, l'autenticazione, la generazione di collegamenti, la valutazione dei criteri e la georilevazione dei client.

Intestazioni inoltrate

Per convenzione, i proxy inoltrano le informazioni nelle intestazioni HTTP.

Intestazione Descrizione
X-Forwarded-For Contiene informazioni sul client che ha avviato la richiesta e sui proxy successivi in una catena di proxy. Questo parametro può contenere indirizzi IP (e, facoltativamente, numeri di porta). In una catena di server proxy, il primo parametro indica il client in cui è stata eseguita inizialmente la richiesta. Seguono gli identificatori dei proxy successivi. L'ultimo proxy della catena non è incluso nell'elenco dei parametri. L'indirizzo IP dell'ultimo proxy e, facoltativamente, un numero di porta sono disponibili come indirizzo IP remoto a livello di trasporto.
X-Forwarded-Proto Il valore dello schema di origine (HTTP/HTTPS). Il valore può essere anche un elenco di schemi, se la richiesta ha attraversato più proxy.
X-Forwarded-Host Il valore originale del campo dell'intestazione host. I proxy in genere non modificano l'intestazione host. Vedere l'avviso di sicurezza Microsoft CVE-2018-0787 per informazioni su una vulnerabilità di elevazione dei privilegi che interessa i sistemi in cui il proxy non convalida o limita le intestazioni host a valori di riferimento noti.

Il middleware delle intestazioni inoltrate (ForwardedHeadersMiddleware), legge queste intestazioni e compila i campi associati in HttpContext.

Il middleware aggiorna:

Per altre informazioni sull'esempio precedente, vedere questo problema di GitHub.

È possibile configurare le impostazioni predefinite del middleware delle intestazioni inoltrate. Per le impostazioni predefinite:

  • È presente un solo proxy tra l'app e l'origine delle richieste.
  • Sono configurati indirizzi di loopback solo per reti e proxy noti.
  • Le intestazioni inoltrate sono denominate X-Forwarded-For e X-Forwarded-Proto.
  • Il ForwardedHeaders valore è ForwardedHeaders.None, i server d'inoltro desiderati devono essere impostati qui per abilitare il middleware.

Non tutte le appliance di rete aggiungono le intestazioni X-Forwarded-For e X-Forwarded-Proto senza alcuna configurazione aggiuntiva. Se le richieste trasmesse tramite proxy non contengono queste intestazioni quando raggiungono l'app, fare riferimento alle indicazioni del produttore dell'appliance. Se l'appliance usa nomi di intestazione diversi da X-Forwarded-For e X-Forwarded-Proto, impostare le opzioni ForwardedForHeaderName e ForwardedProtoHeaderName in modo che corrispondano ai nomi di intestazione usati dall'appliance. Per altre informazioni, vedere Opzioni del middleware delle intestazioni inoltrate e Configurazione per un proxy che usa nomi di intestazione diversi.

IIS/IIS Express e modulo Core ASP.NET

Il middleware delle intestazioni inoltrate è abilitato per impostazione predefinita dal middleware di integrazione IIS quando l'app è ospitata out-of-process dietro IIS e il modulo ASP.NET Core. Il middleware delle intestazioni inoltrate viene attivato per l'esecuzione prima nella pipeline del middleware con una configurazione con restrizioni specifica per il modulo ASP.NET Core per motivi di attendibilità delle intestazioni inoltrate, ad esempio lo spoofing degli indirizzi IP. Il middleware è configurato per inoltrare le intestazioni X-Forwarded-For e X-Forwarded-Proto ed è limitato a un singolo proxy localhost. Se è richiesta una configurazione aggiuntiva, vedere Opzioni del middleware delle intestazioni inoltrate.

Altri scenari con server proxy e servizi di bilanciamento del carico

Se non si usa il middleware di integrazione IIS per l'hosting out-of-process, il middleware delle intestazioni inoltrate non è abilitato per impostazione predefinita. Il middleware delle intestazioni inoltrate deve essere abilitato per consentire a un'app di inoltrare le intestazioni inoltrate del processo con UseForwardedHeaders. Dopo aver abilitato il middleware, se non sono specificate opzioni ForwardedHeadersOptions per il middleware, le intestazioni ForwardedHeadersOptions.ForwardedHeaders predefinite sono ForwardedHeaders.None.

Configurare il middleware con ForwardedHeadersOptions per l'inoltro delle intestazioni X-Forwarded-For e X-Forwarded-Proto in Startup.ConfigureServices.

Ordine del middleware delle intestazioni inoltrate

Il middleware delle intestazioni inoltrate deve essere eseguito prima di altro middleware. Questo ordine garantisce che il middleware basato sulle intestazioni inoltrate possa usare i valori di intestazione per l'elaborazione. Il middleware delle intestazioni inoltrate può essere eseguito dopo la diagnostica e la gestione degli errori, ma deve essere eseguito prima di chiamare 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?}");
        });
    }
}

In alternativa, chiamare UseForwardedHeaders prima della diagnostica:

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

Se non vengono specificate ForwardedHeadersOptions in Startup.ConfigureServices o direttamente nel metodo di estensione con UseForwardedHeaders, le intestazioni predefinite da inoltrare sono ForwardedHeaders.None. La proprietà ForwardedHeaders deve essere configurata con le intestazioni da inoltrare.

Configurazione Nginx

Per inoltrare le X-Forwarded-For intestazioni e X-Forwarded-Proto , vedere Host ASP.NET Core in Linux con Nginx. Per altre informazioni, vedere NGINX: Using the Forwarded header (NGINX: Uso dell'intestazione Forwarded).

Configurazione Apache

X-Forwarded-For viene aggiunta automaticamente. Vedere Apache Module mod_proxy: Reverse Proxy Request Headers (Modulo Apache mod_proxy: Intestazioni delle richieste del proxy inverso). Per informazioni su come inoltrare l'intestazione X-Forwarded-Proto , vedere Host ASP.NET Core in Linux con Apache.

Opzioni del middleware delle intestazioni inoltrate

ForwardedHeadersOptions controllano il comportamento del middleware delle intestazioni inoltrate. L'esempio seguente modifica i valori predefiniti:

  • Limitare il numero di voci nelle intestazioni inoltrate a 2.
  • Aggiungere un indirizzo proxy noto di 127.0.10.1.
  • Modificare il nome dell'intestazione inoltrata dal nome predefinito X-Forwarded-For a X-Forwarded-For-My-Custom-Header-Name.
services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardLimit = 2;
    options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
    options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
Opzione Descrizione
AllowedHosts Limita gli host mediante l'intestazione X-Forwarded-Host ai valori specificati.
  • I valori vengono confrontati tramite ordinal-ignore-case.
  • I numeri di porta devono essere esclusi.
  • Se l'elenco è vuoto, sono consentiti tutti gli host.
  • Un carattere jolly di primo livello * consente tutti gli host non vuoti.
  • I caratteri jolly per i sottodomini sono consentiti, ma non corrispondono al dominio radice. Ad esempio, *.contoso.com corrisponde al sottodominio foo.contoso.com, ma non al dominio radice contoso.com.
  • I nomi host Unicode sono consentiti ma vengono convertiti in Punycode per la corrispondenza.
  • Gli indirizzi IPv6 devono includere le parentesi quadre di delimitazione ed essere in formato convenzionale, ad esempio [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]. Per gli indirizzi IPv6 non viene applicata la distinzione tra maiuscole e minuscole per la verifica dell'uguaglianza logica tra i diversi formati e non viene eseguita alcuna canonizzazione.
  • La mancata limitazione degli host consentiti potrebbe permettere a un utente malintenzionato di eseguire lo spoofing dei collegamenti generati dal servizio.
Il valore predefinito è un insieme IList<string> vuoto.
ForwardedForHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedForHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-For ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-For.
ForwardedHeaders Identifica i server d'inoltro che devono essere elaborati. Vedere ForwardedHeaders Enum (Enumerazione ForwardedHeaders) per l'elenco dei campi applicabili. I valori tipici assegnati a questa proprietà sono ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Il valore predefinito è ForwardedHeaders.None.
ForwardedHostHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedHostHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-Host ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-Host.
ForwardedProtoHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedProtoHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-Proto ma usa un'altra intestazione per inoltrare le informazioni.

Il valore predefinito è X-Forwarded-Proto.
ForwardLimit Limita il numero di voci nelle intestazioni elaborate. Impostare su null per disabilitare il limite, ma solo se è configurato KnownProxies o KnownNetworks. L'impostazione di un valore non null è una precauzione (ma non una garanzia) per proteggersi da proxy non configurati correttamente e richieste dannose provenienti da canali laterali in rete.

Il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso da destra a sinistra. Se viene usato il valore predefinito (1), viene elaborato solo il valore più a destra delle intestazioni, a meno che non venga aumentato il valore di ForwardLimit.

Il valore predefinito è 1.
KnownNetworks Intervalli di indirizzi delle reti note da cui accettare le intestazioni inoltrate. Specificare gli intervalli IP usando la notazione CIDR (Classless Interdomain Routing).

Se il server usa socket dual mode, gli indirizzi IPv4 vengono forniti in un formato IPv6 (ad esempio, 10.0.0.1 in IPv4 rappresentato in IPv6 come ::ffff:10.0.0.1). Vedere IPAddress.MapToIPv6. Determinare se questo formato è richiesto esaminando HttpContext.Connection.RemoteIpAddress.

Il valore predefinito è un oggetto IList><IPNetworkcontenente una singola voce per .IPAddress.Loopback
KnownProxies Indirizzi dei proxy noti da cui accettare le intestazioni inoltrate. Usare KnownProxies per specificare le corrispondenze esatte degli indirizzi IP.

Se il server usa socket dual mode, gli indirizzi IPv4 vengono forniti in un formato IPv6 (ad esempio, 10.0.0.1 in IPv4 rappresentato in IPv6 come ::ffff:10.0.0.1). Vedere IPAddress.MapToIPv6. Determinare se questo formato è richiesto esaminando HttpContext.Connection.RemoteIpAddress.

Il valore predefinito è un oggetto IList><IPAddresscontenente una singola voce per .IPAddress.IPv6Loopback
OriginalForHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalForHeaderName.

Il valore predefinito è X-Original-For.
OriginalHostHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalHostHeaderName.

Il valore predefinito è X-Original-Host.
OriginalProtoHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalProtoHeaderName.

Il valore predefinito è X-Original-Proto.
RequireHeaderSymmetry Richiedere il numero di valori di intestazione da sincronizzare tra le intestazioni ForwardedHeadersOptions.ForwardedHeaders in fase di elaborazione.

Il valore predefinito in ASP.NET Core 1.x è true. Il valore predefinito in ASP.NET Core 2.0 o versione successiva è false.

Scenari e casi d'uso

Quando non è possibile aggiungere le intestazioni inoltrate e tutte le richieste sono sicure

In alcuni casi, potrebbe non essere possibile aggiungere le intestazioni inoltrate alle richieste trasmesse tramite proxy all'app. Se il proxy impone che tutte le richieste esterne pubbliche siano HTTPS, lo schema può essere impostato manualmente in Startup.Configure prima di usare qualsiasi tipo di middleware:

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

Questo codice può essere disabilitato tramite una variabile di ambiente o un'altra impostazione di configurazione in un ambiente di sviluppo o di gestione temporanea.

Gestire la base del percorso e i proxy che modificano il percorso della richiesta

Alcuni proxy passano il percorso senza modifiche, ma con un percorso di base dell'app che deve essere rimosso per consentire il corretto funzionamento del routing. Il middleware UsePathBaseExtensions.UsePathBase suddivide il percorso in HttpRequest.Path e il percorso di base dell'app in HttpRequest.PathBase.

Se /foo è il percorso di base dell'app per un percorso proxy passato come /foo/api/1, il middleware imposta Request.PathBase su /foo e Request.Path su /api/1 con il comando seguente:

app.UsePathBase("/foo");

Il percorso originale e la base del percorso vengono riapplicati quando il middleware viene chiamato nuovamente in direzione inversa. Per altre informazioni sull'elaborazione degli ordini middleware, vedere ASP.NET Middleware core.

Se il proxy taglia il percorso (ad esempio, inoltrando /foo/api/1 a /api/1), correggere i reindirizzamenti e i collegamenti impostando la proprietà PathBase della richiesta:

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

Se il proxy aggiunge i dati del percorso, eliminare parte del percorso per correggere i reindirizzamenti e i collegamenti usando StartsWithSegments ed eseguendo l'assegnazione alla proprietà Path:

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

    return next();
});

Configurazione per un proxy che usa nomi di intestazione diversi

Se il proxy non usa intestazioni denominate X-Forwarded-For e X-Forwarded-Proto per inoltrare l'indirizzo proxy o la porta e le informazioni dello scherma originali, impostare le opzioni ForwardedForHeaderName e ForwardedProtoHeaderName in modo che corrispondano ai nomi di intestazione usati dal 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";
});

Inoltrare lo schema per Linux e proxy inversi non IIS

Con le app che chiamano UseHttpsRedirection e UseHsts il sito si ritrova in un ciclo infinito se distribuito in un servizio app Linux di Azure, in una macchina virtuale Linux di Azure o dietro eventuali altri proxy inversi diversi da IIS. TLS viene terminato dal proxy inverso e Kestrel non è a conoscenza dello schema di richiesta corretto. Si verificano errori anche per OAuth e OIDC in questa configurazione perché generano reindirizzamenti non corretti. UseIISIntegration aggiunge e configura il middleware delle intestazioni inoltrate in caso di esecuzione dietro IIS, ma non esiste alcuna configurazione automatica corrispondente per Linux (integrazione di Apache o Nginx).

Per inoltrare lo schema dal proxy in scenari non IIS, aggiungere e configurare il middleware delle intestazioni inoltrate. In Startup.ConfigureServices usare il codice seguente:

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

Inoltro di certificati

Azure

Per configurare app Azure Servizio per l'inoltro dei certificati, vedere Configurare l'autenticazione reciproca TLS per app Azure Servizio. Le indicazioni seguenti riguardano la configurazione dell'app ASP.NET Core.

In Startup.Configureaggiungere il codice seguente prima della chiamata a app.UseAuthentication();:

app.UseCertificateForwarding();

Configurare il middleware di inoltro certificati per specificare il nome dell'intestazione usato da Azure. In Startup.ConfigureServicesaggiungere il codice seguente per configurare l'intestazione da cui il middleware compila un certificato:

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

Altri proxy Web

Se viene usato un proxy che non è IIS o app Azure Service's Application Request Routing (ARR), configurare il proxy per inoltrare il certificato ricevuto in un'intestazione HTTP. In Startup.Configureaggiungere il codice seguente prima della chiamata a app.UseAuthentication();:

app.UseCertificateForwarding();

Configurare il middleware di inoltro certificati per specificare il nome dell'intestazione. In Startup.ConfigureServicesaggiungere il codice seguente per configurare l'intestazione da cui il middleware compila un certificato:

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

Se il proxy non esegue la codifica base64 del certificato (come nel caso di Nginx), impostare l'opzione HeaderConverter . Si consideri l'esempio seguente in 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;
    }
});

Risoluzione dei problemi

Quando le intestazioni non vengono inoltrate come previsto, abilitare la registrazione. Se i log non forniscono informazioni sufficienti per risolvere il problema, enumerare le intestazioni delle richieste ricevute dal server. Usare il middleware inline per scrivere le intestazioni di richiesta in una risposta dell'app o per registrare le intestazioni.

Per scrivere le intestazioni nella risposta dell'app, aggiungere il middleware inline di terminale seguente immediatamente dopo la chiamata a UseForwardedHeaders in 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}");
});

È possibile scrivere nei log invece che nel corpo della risposta. La scrittura nei log permette il normale funzionamento del sito durante il debug.

Per scrivere nei log invece che nel corpo della risposta:

  • Inserire ILogger<Startup> nella classe Startup come descritto in Creare log in Startup.
  • Aggiungere il middleware inline seguente immediatamente dopo la chiamata a UseForwardedHeaders in Startup.Configure.
app.Use(async (context, next) =>
{
    // Request method, scheme, and 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);

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

Durante l'elaborazione, i valori di X-Forwarded-{For|Proto|Host} vengono spostati in X-Original-{For|Proto|Host}. Se sono presenti più valori in una determinata intestazione, il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso da destra a sinistra. Il valore predefinito di ForwardLimit è 1 (uno) e, pertanto, viene elaborato solo il valore più a destra delle intestazioni, a meno che non venga aumentato il valore di ForwardLimit.

L'indirizzo IP remoto originale della richiesta deve corrispondere a una voce negli elenchi KnownProxies o KnownNetworks prima dell'elaborazione delle intestazioni inoltrate. Questo riduce lo spoofing delle intestazioni, non accettando server di inoltro da proxy non attendibili. Quando viene rilevato un proxy sconosciuto, la registrazione indica l'indirizzo del proxy:

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

Nell'esempio precedente, 10.0.0.100 è un server proxy. Se il server è un proxy attendibile, aggiungere l'indirizzo IP del server a KnownProxies (o aggiungere una rete attendibile a KnownNetworks) in Startup.ConfigureServices. Per altre informazioni, vedere la sezione Opzioni del middleware delle intestazioni inoltrate.

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

Importante

Consentire solo a reti e proxy attendibili di inoltrare le intestazioni. In caso contrario, possono verificarsi attacchi di spoofing degli indirizzi IP.

Risorse aggiuntive