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 8 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 8 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 al client. |
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'intestazioneX-Forwarded-For
. Impostazioni aggiuntive influiscono sul modo in cui il middleware impostaRemoteIpAddress
. Per informazioni dettagliate, vedere Opzioni del middleware delle intestazioni inoltrate. I valori utilizzati vengono rimossi daX-Forwarded-For
e il valore precedente diHttpContext.Connection.RemoteIpAddress
viene salvato in modo permanente inX-Original-For
. Nota: questo processo può essere ripetuto più volte se sono presenti più valori inX-Forwarded-For/Proto/Host/Prefix
, con conseguente spostamento di diversi valori inX-Original-*
, incluso l'originaleRemoteIpAddress/Host/Scheme/PathBase
.HttpContext.Request.Scheme
: impostare usando il valore dell'intestazioneX-Forwarded-Proto
. Il valore utilizzato viene rimosso daX-Forwarded-Proto
e il valore precedente diHttpContext.Request.Scheme
viene salvato in modo permanente inX-Original-Proto
.HttpContext.Request.Host
: impostare usando il valore dell'intestazioneX-Forwarded-Host
. Il valore utilizzato viene rimosso daX-Forwarded-Host
e il valore precedente diHttpContext.Request.Host
viene salvato in modo permanente inX-Original-Host
.HttpContext.Request.PathBase
: impostare usando il valore dell'intestazioneX-Forwarded-Prefix
. Il valore utilizzato viene rimosso daX-Forwarded-Prefix
e il valore precedente diHttpContext.Request.PathBase
viene salvato in modo permanente inX-Original-Prefix
.
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-Host
X-Forwarded-Proto
eX-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, 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.
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
aX-Forwarded-For-My-Custom-Header-Name
.
using System.Net;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
var app = builder.Build();
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Opzione | Descrizione |
---|---|
AllowedHosts | Limita gli host mediante l'intestazione X-Forwarded-Host ai valori specificati.
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 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 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 .new IPNetwork(IPAddress.Loopback, 8) |
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 KnownProxies
o 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:
- HttpContext.Connection.RemoteIpAddress: impostare usando il valore dell'intestazione
X-Forwarded-For
. Impostazioni aggiuntive influiscono sul modo in cui il middleware impostaRemoteIpAddress
. Per informazioni dettagliate, vedere Opzioni del middleware delle intestazioni inoltrate. I valori utilizzati vengono rimossi daX-Forwarded-For
e i valori precedenti vengono salvati in modo permanente inX-Original-For
. Lo stesso criterio viene applicato alle altre intestazioniHost
eProto
. - HttpContext.Request.Scheme: impostare usando il valore dell'intestazione
X-Forwarded-Proto
. - HttpContext.Request.Host: impostare 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
eX-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).
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
aX-Forwarded-For-My-Custom-Header-Name
.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
Opzione | Descrizione |
---|---|
AllowedHosts | Limita gli host mediante l'intestazione X-Forwarded-Host ai valori specificati.
IList<string> vuoto. |
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. |
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 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 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 .new IPNetwork(IPAddress.Loopback, 8) |
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 . |
OriginalPrefixHeaderName | Usare l'intestazione specificata da questa proprietà anziché quella specificata da ForwardedHeadersDefaults.XOriginalPrefixHeaderName. Il valore predefinito è X-Original-Prefix . |
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.Configure
aggiungere 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.ConfigureServices
aggiungere 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.Configure
aggiungere 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.ConfigureServices
aggiungere 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 classeStartup
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, 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 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.