Condividi tramite


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

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

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.
X-Forwarded-Prefix Percorso di base originale richiesto dal client. Questa intestazione può essere utile per le applicazioni per generare correttamente URL, reindirizzamenti o collegamenti di ritorno al cliente.

Forwarded Headers Middleware, 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, X-Forwarded-Proto, X-Forwarded-Host e X-Forwarded-Prefix.
  • 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, consultare le linee guida del produttore del dispositivo. 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 ASP.NET Core Module

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 il Modulo ASP.NET Core (ANCM) per IIS. Il middleware delle intestazioni inoltrate viene attivato per funzionare prima nella pipeline del middleware con una configurazione specifica e limitata del modulo ASP.NET Core. La configurazione con restrizioni è dovuta a preoccupazioni 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 per le intestazioni inoltrate.

Altri scenari con server proxy e servizi di bilanciamento del carico

Al di fuori dell'uso dell'integrazione IIS quando si ospita 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 elaborare le intestazioni inoltrate 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 intestazioni X-Forwarded-For e X-Forwarded-Proto.

Ordine delle intestazioni inoltrate nel middleware

Il middleware delle intestazioni inoltrate deve essere eseguito prima di altri middleware. Questo ordine garantisce che il middleware che si basa su intestazioni inoltrate possa usare i valori delle intestazioni per l'elaborazione. Il middleware delle intestazioni inoltrate può essere eseguito dopo la diagnostica ed 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, consultare Host ASP.NET Core su 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.

Opzioni del middleware per le 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 wildcard per i sottodomini sono consentiti, ma non corrispondono al dominio principale. 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]. Gli indirizzi IPv6 non sono trattati in modo speciale per verificare l'uguaglianza logica tra i diversi formati e non viene eseguita alcuna canonizzazione.
  • L'impossibilità di limitare gli host consentiti può consentire a un cyberattacker di spoofare i collegamenti generati dal servizio.
Il valore predefinito è un valore 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 processati. Consultare ForwardedHeaders Enum 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 che vengono elaborate. Impostare su null per disabilitare il limite, ma solo se è configurato KnownProxies o KnownNetworks. L'impostazione di un valore nonnull è una precauzione (ma non una garanzia) per la protezione da proxy non configurati in modo errato e richieste dannose provenienti da canali laterali nella rete.

Il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso partendo da destra verso 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<IPNetwork> contenente una singola voce per new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Indirizzi dei proxy noti da cui accettare le intestazioni di inoltro. 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<IPAddress> contenente 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 che il numero di valori delle intestazioni sia sincronizzato tra i 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();

Lavora con la base del percorso e i proxy che alterano 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 in .NET 5 a .NET 6), app.UseRouting deve essere chiamato dopo UsePathBase in modo che il middleware di routing possa osservare il percorso modificato prima delle route corrispondenti. In caso contrario, le route vengono confrontate prima che il percorso venga riscritto da UsePathBase come descritto in ASP.NET core middleware e routing in ASP.NET Core.

Il percorso originale e la base del percorso vengono riapplicati quando il middleware viene chiamato nuovamente in direzione inversa. Per ulteriori informazioni sul middleware per l'elaborazione degli ordini, vedere ASP.NET Core Middleware.

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 del proxy e la porta e le informazioni sullo schema originale, impostare le opzioni ForwardedForHeaderName e ForwardedProtoHeaderName in modo che corrispondano ai nomi delle intestazioni 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();

Reindirizzare lo schema per Linux e i proxy inversi diversi da 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 delle intestazioni dal proxy in scenari non IIS, abilitare il Middleware Intestazioni Inoltrate impostando ASPNETCORE_FORWARDEDHEADERS_ENABLED su true. Avviso: questo flag utilizza impostazioni progettate per gli ambienti cloud e non abilita funzionalità come il KnownProxies option per limitare da quali indirizzi IP vengono accettati i server di inoltro.

Inoltro di certificati

Azzurro

Per configurare Azure App Service per l'inoltro dei certificati, vedere Configurare l'autenticazione reciproca di TLS per Azure App Service. Le indicazioni seguenti riguardano la configurazione dell'app 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();

Altri proxy Web

Se viene utilizzato un proxy che non è né IIS né Application Request Routing (ARR) di Azure App Service, configurare il proxy per inoltrare il certificato ricevuto attraverso 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 inoltri 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, consultare 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

Consenti solo a proxy e reti 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:

  • HttpContext.Connection.RemoteIpAddress: impostare usando il valore dell'intestazione X-Forwarded-For . Impostazioni aggiuntive influiscono sul modo in cui il middleware imposta RemoteIpAddress. Per informazioni dettagliate, consultare le opzioni del Middleware Intestazioni Inoltrate. I valori utilizzati vengono rimossi da X-Forwarded-Fore i valori precedenti vengono salvati in modo permanente in X-Original-For. Lo stesso schema viene applicato alle altre intestazioni Host e Proto.
  • HttpContext.Request.Scheme: impostato usando il valore dell'intestazione X-Forwarded-Proto.
  • HttpContext.Request.Host: viene impostato usando il valore dell'intestazione X-Forwarded-Host.

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, consultare le linee guida del produttore del dispositivo. 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 ASP.NET Core Module

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 essere eseguito per primo nella pipeline del middleware con una configurazione limitata specifica per il modulo ASP.NET Core a causa di problemi di fiducia con le intestazioni inoltrate, ad esempio il 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 per le intestazioni inoltrate.

Altri scenari con server proxy e servizi di bilanciamento del carico

Al di fuori dell'uso del 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 elaborare le intestazioni inoltrate 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 intestazioni X-Forwarded-For e X-Forwarded-Proto in Startup.ConfigureServices.

Ordine delle intestazioni inoltrate nel middleware

Il middleware delle intestazioni inoltrate deve essere eseguito prima degli altri middleware. Questo ordine garantisce che il middleware che si basa su intestazioni inoltrate possa usare i valori delle intestazioni per l'elaborazione. Il middleware delle intestazioni inoltrate può essere eseguito dopo la diagnostica ed 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, consultare Host ASP.NET Core su 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).

Opzioni del middleware per le intestazioni inoltrate

ForwardedHeadersOptions controlla 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 wildcard per i sottodomini sono consentiti, ma non corrispondono al dominio principale. 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]. Gli indirizzi IPv6 non sono trattati in modo speciale per verificare l'uguaglianza logica tra i diversi formati e non viene eseguita alcuna canonizzazione.
  • L'impossibilità di limitare gli host consentiti può consentire a un cyberattacker di spoofare i collegamenti generati dal servizio.
Il valore predefinito è un valore IList<string> vuoto.
ForwardedHeaders Identifica i server d'inoltro che devono essere processati. Consultare ForwardedHeaders Enum per l'elenco dei campi applicabili. I valori tipici assegnati a questa proprietà sono ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Il valore predefinito è ForwardedHeaders.None.
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.
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.
ForwardedPrefixHeaderName Utilizzare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XForwardedPrefixHeaderName. Questa opzione viene usata quando il proxy o il server d'inoltro non usa l'intestazione X-Forwarded-Prefix ma usa un'altra intestazione per inoltrare le informazioni.

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

Il middleware delle intestazioni inoltrate elabora le intestazioni in ordine inverso partendo da destra verso 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<IPNetwork> contenente una singola voce per new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Indirizzi dei proxy noti da cui accettare le intestazioni di inoltro. 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<IPAddress> contenente 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.
OriginalPrefixHeaderName Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalPrefixHeaderName.

Il valore predefinito è X-Original-Prefix.
RequireHeaderSymmetry Richiedere che il numero di valori delle intestazioni sia sincronizzato tra i 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 ulteriori informazioni sull'elaborazione degli ordini tramite middleware, vedere ASP.NET Core Middleware.

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 con i nomi X-Forwarded-For e X-Forwarded-Proto per inoltrare l'indirizzo o la porta del proxy e le informazioni dello schema 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 per le intestazioni inoltrate quando viene eseguito dietro IIS, ma non esiste una configurazione automatica corrispondente per Linux (integrazione con Apache o Nginx).

Per inoltrare lo schema dal proxy in scenari non IIS, aggiungere e configurare il middleware "Forwarded Headers". 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

Azzurro

Per configurare Azure App Service per l'inoltro dei certificati, vedere Configurare l'autenticazione reciproca di TLS per Azure App Service. 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 utilizzato un proxy che non è né IIS né Application Request Routing (ARR) di Azure App Service, configurare il proxy per inoltrare il certificato ricevuto attraverso 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'applicazione o per registrare le intestazioni.

Per scrivere le intestazioni nella risposta dell'app, aggiungere il middleware di terminale inline 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:

  • ILogger<Startup> Inserire nella Startup classe come descritto in Creare messaggi di log.
  • Posizionare il middleware inline seguente immediatamente dopo la chiamata a UseForwardedHeaders in Startup.Configure.
app.Use(async (context, next) =>
{
    // Request method, scheme, path, and base path
    _logger.LogDebug("Request Method: {Method}", context.Request.Method);
    _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
    _logger.LogDebug("Request Path: {Path}", context.Request.Path);
    _logger.LogDebug("Request Path Base: {PathBase}", context.Request.PathBase);

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

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

    await next();
});

Durante l'elaborazione, i valori di X-Forwarded-{For|Proto|Host|Prefix} vengono spostati in X-Original-{For|Proto|Host|Prefix}. 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 inoltri 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, consultare la sezione Opzioni del middleware delle intestazioni inoltrate.

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

Importante

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

Risorse aggiuntive