Konfigurieren von ASP.NET Core zur Verwendung mit Proxyservern und Lastenausgleich

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Warnung

Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der Supportrichtlinie für .NET und .NET Core. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Von Chris Ross

In der für ASP.NET Core empfohlenen Konfiguration wird die App mit dem ASP.NET Core-Modul (ANCM) für IIS, Nginx oder Apache gehostet. Proxyserver, Lastenausgleichsmodule und anderen Netzwerkgeräte verdecken häufig Informationen über die Anforderung, bevor diese die App erreicht:

  • Wenn HTTPS-Anforderungen über HTTP-Proxy ausgeführt werden, geht das ursprüngliche Schema (HTTPS) verloren und muss in einem Header weitergeleitet werden.
  • Da eine App eine Anforderung über den Proxy empfängt und nicht über ihre echte Quelle im Internet oder Unternehmensnetzwerk, muss die ursprüngliche Client-IP-Adresse ebenfalls in einem Header weitergeleitet werden.

Diese Informationen können im Anforderungsprozess, z.B. in Umleitungen, bei der Authentifizierung, der Linkgenerierung, der Richtlinienauswertung und der Client-Geolocation wichtig sein.

Informationen zu Apps, die in einer Webfarm ausgeführt werden sollen, finden Sie unterHosten von ASP.NET Core in einer Webfarm.

Weitergeleitete Header

Gemäß der Konvention leiten Proxys Informationen in HTTP-Headern weiter.

Header BESCHREIBUNG
X-Forwarded-For (XFF) Enthält Informationen zum Client, der die Anforderung und die nachfolgenden Proxys in einer Kette von Proxys initiiert hat. Dieser Parameter kann IP-Adressen und optional Portnummern enthalten. Der erste Parameter in einer Kette von Proxyservern gibt den Client an, auf dem die Anforderung zuerst gesendet wurde. Darauf folgen weitere Proxybezeichner. Der letzte Proxy in der Kette ist nicht in der Liste der Parameter. Die IP-Adresse des letzten Proxys und optional eine Portnummer stehen als Remote IP-Adresse auf der Transportschicht zur Verfügung.
X-Forwarded-Proto (XFP) Der Wert des ursprünglichen Schemas, HTTP oder HTTPS. Der Wert kann auch eine Liste von Schemas sein, wenn die Anforderung mehrere Proxys durchlaufen hat.
X-Forwarded-Host (XFH) Der ursprüngliche Wert des Felds „Hostheader“. In der Regel ändern Proxys den Hostheader nicht. Informationen zu einem Sicherheitsrisiko, das Rechteerweiterungen ermöglicht und sich auf Systeme auswirkt, in denen der Proxy Hostheader nicht validiert oder auf als unbedenklich bekannte Werte beschränkt, finden Sie in der Microsoft-Sicherheitsempfehlung CVE-2018-0787.
X-Forwarded-Prefix Der ursprüngliche Basispfad, der vom Client angefordert wurde. Dieser Header kann für Anwendungen hilfreich sein, um URLs, Umleitungen oder Links zurück zum Client zu generieren.

Die Middleware für weitergeleitete Header, ForwardedHeadersMiddleware, liest die Header und füllt die zugehörigen Felder in HttpContext aus.

Die Middleware aktualisiert:

Weitere Informationen hierzu finden Sie in diesem GitHub-Issue.

Die Standardeinstellungen der Middleware für weitergeleitete Header können konfiguriert werden. Für die Standardeinstellungen:

  • Zwischen App und Quelle der Anforderungen ist nur ein Proxy vorhanden.
  • Loopbackadressen sind für bekannte Proxys und bekannte Netzwerke konfiguriert.
  • Die weitergeleiteten Kopfzeilen werden X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host und X-Forwarded-Prefixbenannt.
  • Der Wert ForwardedHeaders lautet ForwardedHeaders.None, und die gewünschten Forwarder müssen hier festgelegt werden, um die Middleware zu aktivieren.

Beachten Sie, dass bei manchen Netzwerkgeräten eine zusätzliche Konfiguration erforderlich ist, damit die Header X-Forwarded-For und X-Forwarded-Proto hinzugefügt werden. Lesen Sie in der Anleitung des Geräteherstellers nach, wenn über einen Proxy übermittelte Anfragen ohne diese Header in der Anwendung eingehen. Verwendet das Gerät andere Headernamen als X-Forwarded-For und X-Forwarded-Proto, passen Sie die Optionen ForwardedForHeaderName und ForwardedProtoHeaderName entsprechend an. Weitere Informationen finden Sie in den Abschnitten Middleware für weitergeleitete Header: Optionen und Konfiguration für einen Proxy, der andere Headernamen nutzt.

IIS-/IIS Express und ASP.NET Core-Modul

Middleware für weitergeleitete Header wird standardmäßig durch Middleware für die Integration von IIS aktiviert, wenn die App hinter IIS und dem ASP.NET Core-Modul (ANCM) für IIS von einem Out-of-Process-Host gehostet wird. Middleware für weitergeleitete Header wird aktiviert, damit sie zuerst in der Middlewarepipeline mit einer eingeschränkten Konfiguration speziell für das ASP.NET Core-Modul ausgeführt wird. Die eingeschränkte Konfiguration wird aufgrund der Sicherheitsbedenken bei weitergeleiteten Headern angewendet, z. B. im Hinblick auf IP-Spoofing. Die Middleware wird so konfiguriert, dass sie die Header X-Forwarded-For und X-Forwarded-Proto weiterleitet, und ist auf einen einzelnen localhost-Proxy beschränkt. Wenn zusätzliche Konfigurationsschritte erforderlich sind, finden Sie weitere Informationen unter Middleware für weitergeleitete Header: Optionen.

Andere Proxyserver- und Lastenausgleichsszenarios

Abgesehen von der Verwendung zur IIS-Integration wird Middleware für weitergeleitete Header beim Out-of-Process-Hosting nicht standardmäßig aktiviert. Middleware für weitergeleitete Header muss aktiviert sein, damit eine App weitergeleitete Header mit UseForwardedHeaders verarbeitet. Sind nach der Aktivierung der Middleware keine ForwardedHeadersOptions für die Middleware angegeben, sind die standardmäßigen ForwardedHeadersOptions gleich ForwardedHeaders.None.

Konfigurieren Sie die Middleware mit ForwardedHeadersOptions so, dass die Header X-Forwarded-For und X-Forwarded-Proto weitergeleitet werden.

Middleware für weitergeleitete Header: Auftrag

Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Die Middleware für weitergeleitete Header kann nach der Diagnose und Fehlerbehandlung ausgeführt werden. Sie muss jedoch vor dem Aufrufen von UseHstsausgeführt werden:

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

Rufen Sie alternativ vor der Diagnose UseForwardedHeaders auf:

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

Hinweis

Sind keine ForwardedHeadersOptions in UseForwardedHeaders oder direkt für die Erweiterungsmethode angegeben, entsprechen die weiterzuleitenden Standardheader ForwardedHeadersOptions. Die ForwardedHeaders-Eigenschaft muss mit den weiterzuleitenden Headern konfiguriert werden.

Nginx-Konfiguration

Informationen zur Weiterleitung der Header X-Forwarded-For und X-Forwarded-Proto finden Sie unter X-Forwarded-For. Weitere Informationen finden Sie unter NGINX: Using the Forwarded header (NGINX: Verwenden des weitergeleiteten Headers).

Apache-Konfiguration

X-Forwarded-For wird automatisch hinzugefügt. Weitere Informationen finden Sie unter Apache-Modul mod_proxy: Reverseproxy-Anforderungsheader.

Middleware für weitergeleitete Header: Optionen

ForwardedHeadersOptions steuern das Verhalten der ForwardedHeadersOptions. Im folgenden Beispiel werden die Standardwerte geändert:

  • Die Anzahl von Einträgen in den weitergeleiteten Headern wird auf 2 beschränkt.
  • Es wird die bekannte Proxyadresse 127.0.10.1 hinzugefügt.
  • Der Name des weitergeleiteten Headers wird vom Standardwert X-Forwarded-For in den Wert X-Forwarded-For-My-Custom-Header-Name geändert.
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();
Option Beschreibung
AllowedHosts Begrenzt Hosts durch den X-Forwarded-Host-Header auf die angegebenen Werte.
  • Werte werden mit Ordnungszahl/Groß-/Kleinschreibung ignorieren verglichen.
  • Portnummern müssen ausgeschlossen werden.
  • Wenn die Liste leer ist, sind alle Hosts zulässig.
  • Ein Platzhalter * auf der obersten Ebene lässt alle nicht leeren Hosts zu.
  • Unterdomänen-Platzhalter sind zulässig, stimmen aber nicht mit der Stammdomäne überein. Beispielsweise entspricht *.contoso.com der Unterdomäne foo.contoso.com, aber nicht der Stammdomäne contoso.com.
  • Unicode-Hostnamen sind zulässig, werden jedoch für den Abgleich in Punycode konvertiert.
  • IPv6-Adressen müssen Begrenzungsklammern einschließen und im konventionellen Format vorliegen (z.B. [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). IPv6-Adressen sind keine Sonderfälle, um auf logische Gleichheit zwischen verschiedenen Formaten zu prüfen, und es wird keine Kanonisierung durchgeführt.
  • Wenn die zulässigen Hosts nicht eingeschränkt werden, könnten Cyberkriminelle die vom Dienst generierten Links fälschen.
Der Standardwert ist eine leere IList<string>.
ForwardedForHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedForHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-For sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-For.
ForwardedHeaders Gibt an, welche Weiterleitungen verarbeitet werden sollen. Weitere Informationen zur Liste der anzuwendenden Felder finden Sie unter ForwardedHeaders Enum. Typische Werte, die dieser Eigenschaft zugewiesen wurden, sind ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Der Standardwert ist ForwardedHeaders.None.
ForwardedHostHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedHostHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-Host sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-Host.
ForwardedProtoHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedProtoHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-Proto sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-Proto.
ForwardLimit Schränkt die Anzahl der Einträge in den Headern ein, die verarbeitet werden. Legen Sie den Wert null fest, um die Einschränkung zu deaktivieren. Diese Einstellung sollte jedoch nur vorgenommen werden, wenn KnownProxies oder KnownNetworks konfiguriert sind. Das Festlegen eines Werts ungleich null ist eine Vorsichtsmaßnahme (aber keine Garantie) zum Schutz vor falsch konfigurierten Proxys und schädlichen Anforderungen aus Seitenkanälen im Netzwerk.

Die Middleware der Weiterleitungsheader verarbeitet Header in umgekehrter Reihenfolge von rechts nach links. Wenn der Standardwert von (1) verwendet wird, wird nur der äußere rechte Wert aus den Headern verarbeitet, es sei denn, der Wert von ForwardLimit wird erhöht.

Der Standardwert ist 1.
KnownNetworks Adressbereiche bekannter Netzwerke; von dort weitergeleitete Header müssen akzeptiert werden. Geben Sie IP-Adressbereiche mithilfe der CIDR-Notation (Classless Interdomain Routing) an.

Wenn der Server Dualmodussockets verwendet, werden IPv4-Adressen in einem IPv6-Format bereitgestellt (z.B. wird 10.0.0.1 in IPv4 in IPv6 als ::ffff:10.0.0.1 dargestellt). Siehe IPAddress.MapToIPv6. Bestimmen Sie mithilfe der HttpContext.Connection.RemoteIpAddress, ob dieses Format erforderlich ist.

Der Standardwert lautet IList<IPNetwork> mit einem einzelnen Eintrag für new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Adressen bekannter Proxys, von denen weitergeleitete Header akzeptiert werden müssen. Verwenden Sie KnownProxies, um genaue IP-Adressübereinstimmungen anzugeben.

Wenn der Server Dualmodussockets verwendet, werden IPv4-Adressen in einem IPv6-Format bereitgestellt (z.B. wird 10.0.0.1 in IPv4 in IPv6 als ::ffff:10.0.0.1 dargestellt). Siehe IPAddress.MapToIPv6. Bestimmen Sie mithilfe der HttpContext.Connection.RemoteIpAddress, ob dieses Format erforderlich ist.

Der Standardwert lautet IList<IPAddress> mit einem einzelnen Eintrag für IPAddress.IPv6Loopback.
OriginalForHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalForHeaderName angegebenen.

Der Standardwert ist X-Original-For.
OriginalHostHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalHostHeaderName angegebenen.

Der Standardwert ist X-Original-Host.
OriginalProtoHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalProtoHeaderName angegebenen.

Der Standardwert ist X-Original-Proto.
RequireHeaderSymmetry Die Anzahl von Headerwerten muss in den ForwardedHeadersOptions.ForwardedHeaders übereinstimmen, die verarbeitet werden.

Die Standardeinstellung in ASP.NET Core 1.x ist true. Die Standardeinstellung in ASP.NET Core 2.0 oder höher ist false.

Szenarios und Anwendungsfälle

Wenn keine weitergeleiteten Header hinzugefügt werden können und alle Anforderungen sicher sind

In einigen Fällen ist es möglicherweise ausgeschlossen, weitergeleitete Header den Anforderungen hinzuzufügen, die über einen Proxy an die App übermittelt werden. Wenn der Proxy erzwingt, dass alle öffentlichen externen Anforderungen HTTPS-Anforderungen sein müssen, kann das Schema manuell festgelegt werden, bevor ein beliebiger Middlewaretyp verwendet wird:

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

Dieser Code kann mit einer Umgebungsvariablen oder einer anderen Konfigurationseinstellung in einer Entwicklungs- oder Stagingumgebung deaktiviert werden:

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

Arbeiten mit Pfadbasis und Proxys, die den Anforderungspfad ändern

Einige Proxys übergeben den Pfad intakt, aber mit einem App-basierten Pfad, der entfernt werden sollte, damit das Routing ordnungsgemäß funktioniert. UsePathBaseExtensions.UsePathBase-Middleware teilt den Pfad in HttpRequest.Path und den App-Basispfad in HttpRequest.PathBase.

Wenn /foo der App-Basispfad für einen als /foo/api/1 übergebenen Proxypfad ist, setzt die Middleware mit dem folgenden Befehl Request.PathBase auf /foo und Request.Path auf /api/1:

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

Hinweis

Wenn Sie WebApplication verwenden (siehe Migrieren von ASP.NET Core 5.0 zu 6.0), muss app.UseRouting nach UsePathBase aufgerufen werden, damit die Routingmiddleware den geänderten Pfad beobachten kann, bevor Routen abgeglichen werden. Andernfalls werden Routen abgeglichen, bevor der Pfad durch UsePathBase neu geschrieben wird. Weitere Informationen hierzu finden Sie in den Artikeln Festlegen der Reihenfolge für Middleware und Routing.

Der ursprüngliche Pfad und die Pfadbasis werden erneut angewendet, wenn die Middleware in umgekehrter Reihenfolge erneut aufgerufen wird. Weitere Informationen zur Reihenfolge der Middlewareverarbeitung finden Sie unter ASP.NET Core-Middleware.

Wenn der Proxy den Pfad abschneidet (z.B. Weiterleitung von /foo/api/1 zu /api/1), korrigieren Sie Umleitungen und Links, indem Sie die Eigenschaft /foo/api/1 der Anforderungen setzen:

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

Wenn der Proxy Pfaddaten hinzufügt, verwerfen Sie einen Teil des Pfads, um Umleitungen und Links zu korrigieren, indem Sie StartsWithSegments verwenden und der Path-Eigenschaft zuweisen:

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

    return next(context);
});

Konfiguration für einen Proxy, der andere Headernamen verwendet

Verwendet der Proxy zum Weiterleiten der Proxyadresse/des Ports und zum Erzeugen der Schemainformationen andere Headernamen als X-Forwarded-For und X-Forwarded-Proto, passen Sie die Optionen ForwardedForHeaderName und ForwardedProtoHeaderName entsprechend an:

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

Das Schema für Linux- und Nicht-IIS-Reverseproxys weiterleiten

Apps, die UseHttpsRedirection und UseHsts aufrufen, versetzen eine Site in eine Endlosschleife, falls die Bereitstellung in einem Azure Linux App Service, auf einem virtuellen Azure Linux-Computer, oder hinter einem anderen Reverseproxy als IIS erfolgt. TLS wird vom Reverseproxy beendet, und Kestrel wird nicht auf das richtige Anforderungsschema aufmerksam gemacht. OAuth und OIDC schlagen in dieser Konfiguration ebenfalls fehl, weil sie falsche Umleitungen generieren. UseIISIntegration fügt die Middleware für weitergeleitete Header hinzu und konfiguriert sie, wenn es hinter IIS ausgeführt wird, aber es gibt keine entsprechende automatische Konfiguration für Linux (Apache- oder Nginx-Integration).

Um das Schema aus dem Proxy in Nicht-IIS-Szenarien weiterzuleiten, aktivieren Sie die Middleware für weitergeleitete Header, indem Sie ASPNETCORE_FORWARDEDHEADERS_ENABLED auf true festlegen. Warnung: Dieses Flag verwendet Einstellungen für Cloudumgebungen und aktiviert keine Features wie die KnownProxies option, um einzuschränken, von welchen IPs Weiterleitungen akzeptiert werden.

Zertifikatweiterleitung

Azure

Informationen zum Konfigurieren von Azure App Service für die Zertifikatsweiterleitung finden Sie unter Konfigurieren der gegenseitigen TLS-Authentifizierung für Azure App Service. Die folgende Anleitung bezieht sich auf die Konfiguration der ASP.NET Core-App.

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

Andere Webproxys

Wenn ein Proxy verwendet wird, der nicht IIS oder Routing von Anwendungsanforderungen von Azure App Service entspricht, konfigurieren Sie den Proxy so, dass das empfangene Zertifikat in einem HTTP-Header weitergeleitet wird.

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

Wenn der Proxy keine Base64-Codierung für das Zertifikat verwendet (wie bei Nginx), legen Sie die Option HeaderConverter fest. Betrachten Sie das folgenden Beispiel:

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

Problembehandlung

Wenn Header nicht wie erwartet weitergeleitet werden, aktivieren Sie die debug auf debug-Ebene und die HTTP-Anforderungsprotokollierung. UseHttpLogging muss nach UseForwardedHeaders aufgerufen werden:

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

Wenn in einem bestimmten Header mehrere Werte vorhanden sind, verarbeitet die Middleware der Weiterleitungsheader die Header in umgekehrter Reihenfolge von rechts nach links. Der Standardwert von ForwardLimit ist 1 (eins), sodass nur der äußere rechte Wert aus den Headern verarbeitet wird, es sei denn, der Wert von ForwardLimit wird erhöht.

Die ursprüngliche IP-Remoteadresse der Anforderung muss mit einem Eintrag in den KnownProxies- oder KnownNetworks-Listen übereinstimmen, bevor weitergeleitete Header verarbeitet werden. Auf diese Weise wird das Headerspoofing begrenzt, da keine Weiterleitungen von nicht vertrauenswürdigen Proxys akzeptiert werden. Wenn ein unbekannter Proxy erkannt wird, gibt die Protokollierung die Adresse des Proxys an:

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

Im vorherigen Beispiel ist 10.0.0.100 ein Proxyserver. Wenn der Server ein vertrauenswürdiger Proxy ist, fügen Sie KnownNetworks die IP-Adresse des Servers KnownProxies oder ein vertrauenswürdiges Netzwerk hinzu. Weitere Informationen finden Sie im Abschnitt Middleware für weitergeleitete Header: Optionen.

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

Um die Protokolle anzuzeigen, fügen Sie "Microsoft.AspNetCore.HttpLogging": "Information" der Datei appsettings.Development.json hinzu:

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

Wichtig

Erlauben Sie nur vertrauenswürdigen Proxys und Netzwerken die Weiterleitung von Headern. Andernfalls sind Angriffe des Typs IP-Spoofing möglich.

Zusätzliche Ressourcen

In der für ASP.NET Core empfohlenen Konfiguration wird die App mit dem IIS/ASP.NET Core-Modul, Nginx oder Apache gehostet. Proxyserver, Lastenausgleichsmodule und anderen Netzwerkgeräte verdecken häufig Informationen über die Anforderung, bevor diese die App erreicht:

  • Wenn HTTPS-Anforderungen über HTTP-Proxy ausgeführt werden, geht das ursprüngliche Schema (HTTPS) verloren und muss in einem Header weitergeleitet werden.
  • Da eine App eine Anforderung über den Proxy empfängt und nicht über ihre echte Quelle im Internet oder Unternehmensnetzwerk, muss die ursprüngliche Client-IP-Adresse ebenfalls in einem Header weitergeleitet werden.

Diese Informationen können im Anforderungsprozess, z.B. in Umleitungen, bei der Authentifizierung, der Linkgenerierung, der Richtlinienauswertung und der Client-Geolocation wichtig sein.

Weitergeleitete Header

Gemäß der Konvention leiten Proxys Informationen in HTTP-Headern weiter.

Header Beschreibung
X-Forwarded-For Enthält Informationen zum Client, der die Anforderung und die nachfolgenden Proxys in einer Kette von Proxys initiiert hat. Dieser Parameter kann IP-Adressen (und optional Portnummern) enthalten. Der erste Parameter in einer Kette von Proxyservern gibt den Client an, auf dem die Anforderung zuerst gesendet wurde. Darauf folgen weitere Proxybezeichner. Der letzte Proxy in der Kette ist nicht in der Liste der Parameter. Die IP-Adresse des letzten Proxys und optional eine Portnummer stehen als Remote IP-Adresse auf der Transportschicht zur Verfügung.
X-Forwarded-Proto Der Wert des ursprünglichen Schemas (HTTP/HTTPS). Der Wert kann auch eine Liste von Schemas sein, wenn die Anforderung mehrere Proxys durchlaufen hat.
X-Forwarded-Host Der ursprüngliche Wert des Felds „Hostheader“. In der Regel ändern Proxys den Hostheader nicht. Informationen zu einem Sicherheitsrisiko, das Rechteerweiterungen ermöglicht und sich auf Systeme auswirkt, in denen der Proxy Hostheader nicht validiert oder auf als unbedenklich bekannte Werte beschränkt, finden Sie in der Microsoft-Sicherheitsempfehlung CVE-2018-0787.

Die Middleware für weitergeleitete Header (ForwardedHeadersMiddleware) liest die Header und füllt die zugehörigen Felder in HttpContext aus.

Die Middleware aktualisiert:

Weitere Informationen hierzu finden Sie in diesem GitHub-Issue.

Die Standardeinstellungen der Middleware für weitergeleitete Header können konfiguriert werden. Für die Standardeinstellungen:

  • Zwischen App und Quelle der Anforderungen ist nur ein Proxy vorhanden.
  • Loopbackadressen sind für bekannte Proxys und bekannte Netzwerke konfiguriert.
  • Die weitergeleiteten Header heißen X-Forwarded-For und X-Forwarded-Proto.
  • Der Wert ForwardedHeaders lautet ForwardedHeaders.None, und die gewünschten Forwarder müssen hier festgelegt werden, um die Middleware zu aktivieren.

Beachten Sie, dass bei manchen Netzwerkgeräten eine zusätzliche Konfiguration erforderlich ist, damit die Header X-Forwarded-For und X-Forwarded-Proto hinzugefügt werden. Lesen Sie in der Anleitung des Geräteherstellers nach, wenn über einen Proxy übermittelte Anfragen ohne diese Header in der Anwendung eingehen. Verwendet das Gerät andere Headernamen als X-Forwarded-For und X-Forwarded-Proto, passen Sie die Optionen ForwardedForHeaderName und ForwardedProtoHeaderName entsprechend an. Weitere Informationen finden Sie in den Abschnitten Middleware für weitergeleitete Header: Optionen und Konfiguration für einen Proxy, der andere Headernamen nutzt.

IIS-/IIS Express und ASP.NET Core-Modul

Middleware für weitergeleitete Header wird standardmäßig durch Middleware für die Integration von IIS aktiviert, wenn die App hinter IIS und dem ASP.NET Core-Modul von einem Out-of-Process-Host gehostet wird. Middleware für weitergeleitete Header wird aktiviert und zuerst in der Middlewarepipeline mit einer beschränkten Konfiguration ausgeführt, die für das ASP.NET Core-Modul spezifisch ist. Dies ist auf Bedenken in Bezug auf die Vertrauenswürdigkeit von weitergeleiteten Headern zurückzuführen (z.B. IP-Spoofing). Die Middleware wird so konfiguriert, dass sie die Header X-Forwarded-For und X-Forwarded-Proto weiterleitet, und ist auf einen einzelnen localhost-Proxy beschränkt. Wenn zusätzliche Konfigurationsschritte erforderlich sind, finden Sie weitere Informationen unter Middleware für weitergeleitete Header: Optionen.

Andere Proxyserver- und Lastenausgleichsszenarios

Außer bei der Verwendung der Integration von IIS wird die Middleware für weitergeleitete Header nicht standardmäßig aktiviert, wenn sie von einem Out-of-Process-Host gehostet wird. Middleware für weitergeleitete Header muss aktiviert sein, damit eine App weitergeleitete Header mit UseForwardedHeaders verarbeitet. Sind nach der Aktivierung der Middleware keine ForwardedHeadersOptions für die Middleware angegeben, sind die standardmäßigen ForwardedHeadersOptions gleich ForwardedHeaders.None.

Konfigurieren Sie die Middleware mit ForwardedHeadersOptions so, dass die Header X-Forwarded-For und X-Forwarded-Proto in Startup.ConfigureServices weitergeleitet werden.

Middleware für weitergeleitete Header: Auftrag

Middleware für weitergeleitete Header muss vor anderen Middlewarekomponenten ausgeführt werden. Mit dieser Reihenfolge wird sichergestellt, dass die auf Informationen von weitergeleiteten Headern basierende Middleware die zu verarbeitenden Headerwerte nutzen kann. Die Middleware für weitergeleitete Header kann nach der Diagnose und Fehlerbehandlung ausgeführt werden. Sie muss jedoch vor dem Aufrufen von UseHstsausgeführt werden:

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?}");
        });
    }
}

Rufen Sie alternativ vor der Diagnose UseForwardedHeaders auf:

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?}");
    });
}

Hinweis

Sind keine ForwardedHeadersOptions in Startup.ConfigureServices oder direkt für die Erweiterungsmethode mit UseForwardedHeaders angegeben, sind die weiterzuleitenden Standardheader gleich ForwardedHeadersOptions. Die ForwardedHeaders-Eigenschaft muss mit den weiterzuleitenden Headern konfiguriert werden.

Nginx-Konfiguration

Informationen zur Weiterleitung der Header X-Forwarded-For und X-Forwarded-Proto finden Sie unter X-Forwarded-For. Weitere Informationen finden Sie unter NGINX: Using the Forwarded header (NGINX: Verwenden des weitergeleiteten Headers).

Apache-Konfiguration

X-Forwarded-For wird automatisch hinzugefügt (siehe X-Forwarded-For).

Middleware für weitergeleitete Header: Optionen

ForwardedHeadersOptions steuern das Verhalten der Middleware für weitergeleitete Header. Im folgenden Beispiel werden die Standardwerte geändert:

  • Beschränken Sie die Zahl der Einträge in den weitergeleiteten Headern auf 2.
  • Fügen Sie eine bekannte Proxyadresse von 127.0.10.1 hinzu.
  • Ändern Sie den Namen des weitergeleiteten Headers vom Standardwert X-Forwarded-For in den Wert 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";
});
Option Beschreibung
AllowedHosts Begrenzt Hosts durch den X-Forwarded-Host-Header auf die angegebenen Werte.
  • Werte werden mit Ordnungszahl/Groß-/Kleinschreibung ignorieren verglichen.
  • Portnummern müssen ausgeschlossen werden.
  • Wenn die Liste leer ist, sind alle Hosts zulässig.
  • Ein Platzhalter * auf der obersten Ebene lässt alle nicht leeren Hosts zu.
  • Unterdomänen-Platzhalter sind zulässig, stimmen aber nicht mit der Stammdomäne überein. Beispielsweise entspricht *.contoso.com der Unterdomäne foo.contoso.com, aber nicht der Stammdomäne contoso.com.
  • Unicode-Hostnamen sind zulässig, werden jedoch für den Abgleich in Punycode konvertiert.
  • IPv6-Adressen müssen Begrenzungsklammern einschließen und im konventionellen Format vorliegen (z.B. [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). IPv6-Adressen sind keine Sonderfälle, um auf logische Gleichheit zwischen verschiedenen Formaten zu prüfen, und es wird keine Kanonisierung durchgeführt.
  • Wenn die zulässigen Hosts nicht eingeschränkt werden, könnten Cyberkriminelle die vom Dienst generierten Links fälschen.
Der Standardwert ist eine leere IList<string>.
ForwardedHeaders Gibt an, welche Weiterleitungen verarbeitet werden sollen. Weitere Informationen zur Liste der anzuwendenden Felder finden Sie unter ForwardedHeaders Enum. Typische Werte, die dieser Eigenschaft zugewiesen wurden, sind ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Der Standardwert ist ForwardedHeaders.None.
ForwardedForHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedForHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-For sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-For.
ForwardedHostHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedHostHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-Host sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-Host.
ForwardedProtoHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XForwardedProtoHeaderName angegebenen. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-Proto sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-Proto.
ForwardedPrefixHeaderName Verwenden Sie die von dieser Eigenschaft angegebene Kopfzeile anstelle der durch ForwardedHeadersDefaults.XForwardedPrefixHeaderNameangegebenen Kopfzeile. Diese Option wird verwendet, wenn beim Proxy/Weiterleitenden nicht der Header X-Forwarded-Prefix sondern ein anderer Header für die Weiterleitung der Informationen genutzt wird.

Der Standardwert ist X-Forwarded-Prefix.
ForwardLimit Schränkt die Anzahl der Einträge in den Headern ein, die verarbeitet werden. Legen Sie den Wert null fest, um die Einschränkung zu deaktivieren. Diese Einstellung sollte jedoch nur vorgenommen werden, wenn KnownProxies oder KnownNetworks konfiguriert sind. Das Festlegen eines Werts ungleich null ist eine Vorsichtsmaßnahme (aber keine Garantie) zum Schutz vor falsch konfigurierten Proxys und schädlichen Anforderungen aus Seitenkanälen im Netzwerk.

Die Middleware der Weiterleitungsheader verarbeitet Header in umgekehrter Reihenfolge von rechts nach links. Wenn der Standardwert von (1) verwendet wird, wird nur der äußere rechte Wert aus den Headern verarbeitet, es sei denn, der Wert von ForwardLimit wird erhöht.

Der Standardwert ist 1.
KnownNetworks Adressbereiche bekannter Netzwerke; von dort weitergeleitete Header müssen akzeptiert werden. Geben Sie IP-Adressbereiche mithilfe der CIDR-Notation (Classless Interdomain Routing) an.

Wenn der Server Dualmodussockets verwendet, werden IPv4-Adressen in einem IPv6-Format bereitgestellt (z.B. wird 10.0.0.1 in IPv4 in IPv6 als ::ffff:10.0.0.1 dargestellt). Siehe IPAddress.MapToIPv6. Bestimmen Sie mithilfe der HttpContext.Connection.RemoteIpAddress, ob dieses Format erforderlich ist.

Der Standardwert lautet IList<IPNetwork> mit einem einzelnen Eintrag für new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Adressen bekannter Proxys, von denen weitergeleitete Header akzeptiert werden müssen. Verwenden Sie KnownProxies, um genaue IP-Adressübereinstimmungen anzugeben.

Wenn der Server Dualmodussockets verwendet, werden IPv4-Adressen in einem IPv6-Format bereitgestellt (z.B. wird 10.0.0.1 in IPv4 in IPv6 als ::ffff:10.0.0.1 dargestellt). Siehe IPAddress.MapToIPv6. Bestimmen Sie mithilfe der HttpContext.Connection.RemoteIpAddress, ob dieses Format erforderlich ist.

Der Standardwert lautet IList<IPAddress> mit einem einzelnen Eintrag für IPAddress.IPv6Loopback.
OriginalForHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalForHeaderName angegebenen.

Der Standardwert ist X-Original-For.
OriginalHostHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalHostHeaderName angegebenen.

Der Standardwert ist X-Original-Host.
OriginalProtoHeaderName Verwenden Sie den Header, der von dieser Eigenschaft angegeben wurde, anstelle des von ForwardedHeadersDefaults.XOriginalProtoHeaderName angegebenen.

Der Standardwert ist X-Original-Proto.
OriginalPrefixHeaderName Verwenden Sie die von dieser Eigenschaft angegebene Kopfzeile anstelle der durch ForwardedHeadersDefaults.XOriginalPrefixHeaderNameangegebenen Kopfzeile.

Der Standardwert ist X-Original-Prefix.
RequireHeaderSymmetry Die Anzahl von Headerwerten muss in den ForwardedHeadersOptions.ForwardedHeaders übereinstimmen, die verarbeitet werden.

Die Standardeinstellung in ASP.NET Core 1.x ist true. Die Standardeinstellung in ASP.NET Core 2.0 oder höher ist false.

Szenarios und Anwendungsfälle

Wenn keine weitergeleiteten Header hinzugefügt werden können und alle Anforderungen sicher sind

In einigen Fällen ist es möglicherweise ausgeschlossen, weitergeleitete Header den Anforderungen hinzuzufügen, die über einen Proxy an die App übermittelt werden. Wenn der Proxy erzwingt, dass alle öffentlichen externen Anforderungen HTTPS-Anforderungen sind, kann das Schema manuell in Startup.Configure festgelegt werden, bevor ein beliebiger Middlewaretyp verwendet wird:

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

Dieser Code kann mit einer Umgebungsvariablen oder einer anderen Konfigurationseinstellung in einer Entwicklungs- oder Stagingumgebung deaktiviert werden.

Umgang mit Pfadbasis und Proxys, die den Anforderungspfad ändern

Einige Proxys übergeben den Pfad intakt, aber mit einem App-basierten Pfad, der entfernt werden sollte, damit das Routing ordnungsgemäß funktioniert. UsePathBaseExtensions.UsePathBase-Middleware teilt den Pfad in HttpRequest.Path und den App-Basispfad in HttpRequest.PathBase.

Wenn /foo der App-Basispfad für einen als /foo/api/1 übergebenen Proxypfad ist, setzt die Middleware mit dem folgenden Befehl Request.PathBase auf /foo und Request.Path auf /api/1:

app.UsePathBase("/foo");

Der ursprüngliche Pfad und die Pfadbasis werden erneut angewendet, wenn die Middleware in umgekehrter Reihenfolge erneut aufgerufen wird. Weitere Informationen zur Reihenfolge der Middlewareverarbeitung finden Sie unter ASP.NET Core-Middleware.

Wenn der Proxy den Pfad abschneidet (z.B. Weiterleitung von /foo/api/1 zu /api/1), korrigieren Sie Umleitungen und Links, indem Sie die Eigenschaft /foo/api/1 der Anforderungen setzen:

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

Wenn der Proxy Pfaddaten hinzufügt, verwerfen Sie einen Teil des Pfads, um Umleitungen und Links zu korrigieren, indem Sie StartsWithSegments verwenden und der Path-Eigenschaft zuweisen:

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

    return next();
});

Konfiguration für einen Proxy, der andere Headernamen verwendet

Verwendet der Proxy zum Weiterleiten der Proxyadresse/des Ports und zum Erzeugen der Schemainformationen andere Headernamen als X-Forwarded-For und X-Forwarded-Proto, passen Sie die Optionen ForwardedForHeaderName und ForwardedProtoHeaderName entsprechend an:

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

Das Schema für Linux- und Nicht-IIS-Reverseproxys weiterleiten

Apps, die UseHttpsRedirection und UseHsts aufrufen, versetzen eine Site in eine Endlosschleife, falls die Bereitstellung in einem Azure Linux App Service, auf einem virtuellen Azure Linux-Computer, oder hinter einem anderen Reverseproxy als IIS erfolgt. TLS wird vom Reverseproxy beendet, und Kestrel wird nicht auf das richtige Anforderungsschema aufmerksam gemacht. OAuth und OIDC schlagen in dieser Konfiguration ebenfalls fehl, weil sie falsche Umleitungen generieren. UseIISIntegration fügt die Middleware für weitergeleitete Header hinzu und konfiguriert sie, wenn es hinter IIS ausgeführt wird, aber es gibt keine entsprechende automatische Konfiguration für Linux (Apache- oder Nginx-Integration).

Um das Schema von dem Proxy in Nicht-IIS-Szenarios weiterzuleiten, fügen Sie die Middleware für weitergeleitete Header hinzu, und konfigurieren Sie sie. In Startup.ConfigureServices verwenden Sie folgenden Code:

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

Zertifikatweiterleitung

Azure

Informationen zum Konfigurieren von Azure App Service für die Zertifikatsweiterleitung finden Sie unter Konfigurieren der gegenseitigen TLS-Authentifizierung für Azure App Service. Die folgende Anleitung bezieht sich auf die Konfiguration der ASP.NET Core-App.

Fügen Sie Startup.Configure direkt vor dem Aufruf von app.UseAuthentication(); den folgenden Code hinzu:

app.UseCertificateForwarding();

Konfigurieren Sie die Middleware für die Zertifikatweiterleitung, um den von Azure verwendeten Headernamen anzugeben. Fügen Sie in Startup.ConfigureServices den folgenden Code hinzu, um den Header zu konfigurieren, anhand dessen die Middleware ein Zertifikat erstellt:

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

Andere Webproxys

Wenn ein Proxy verwendet wird, der nicht IIS oder Routing von Anwendungsanforderungen von Azure App Service entspricht, konfigurieren Sie den Proxy so, dass das empfangene Zertifikat in einem HTTP-Header weitergeleitet wird. Fügen Sie Startup.Configure direkt vor dem Aufruf von app.UseAuthentication(); den folgenden Code hinzu:

app.UseCertificateForwarding();

Konfigurieren Sie die Middleware für die Zertifikatweiterleitung konfigurieren, um den Headernamen anzugeben. Fügen Sie in Startup.ConfigureServices den folgenden Code hinzu, um den Header zu konfigurieren, anhand dessen die Middleware ein Zertifikat erstellt:

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

Wenn der Proxy das Zertifikat mit nicht mit base64 codiert (wie bei Nginx), legen Sie die Option HeaderConverter fest. Betrachten Sie das folgende Beispiel 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;
    }
});

Problembehandlung

Wenn Header nicht wie erwartet zugewiesen werden, aktivieren Sie die Protokollierung. Wenn die Protokolle nicht genügend Informationen zur Problembehandlung bereitstellen, listen Sie die vom Server empfangenen Anforderungsheader auf. Verwenden Sie Inlinemiddleware, um Anforderungsheader in eine App-Antwort zu schreiben oder die Header zu protokollieren.

Um die Header in die Antwort der App zu schreiben, platzieren Sie die folgende Terminalinlinemiddleware unmittelbar hinter den Aufruf von 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}");
});

Statt in den Antworttext können Sie in Protokolle schreiben. Das Schreiben in Protokolle ermöglicht es der Website, während des Debuggens normal zu funktionieren.

So schreiben Sie in Protokolle und nicht in den Antworttext:

  • Fügen Sie ILogger<Startup> in die Startup-Klasse ein, wie unter ILogger<Startup> beschrieben.
  • Platzieren Sie die folgende Inlinemiddleware unmittelbar hinter den Aufruf von 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();
});

Bei der Verarbeitung werden X-Forwarded-{For|Proto|Host|Prefix}-Werte in X-Original-{For|Proto|Host|Prefix} verschoben. Wenn in einem bestimmten Header mehrere Werte vorhanden sind, verarbeitet die Middleware der Weiterleitungsheader die Header in umgekehrter Reihenfolge von rechts nach links. Der Standardwert von ForwardLimit ist 1 (eins), sodass nur der äußere rechte Wert aus den Headern verarbeitet wird, es sei denn, der Wert von ForwardLimit wird erhöht.

Die ursprüngliche IP-Remoteadresse der Anforderung muss mit einem Eintrag in den KnownProxies- oder KnownNetworks-Listen übereinstimmen, bevor weitergeleitete Header verarbeitet werden. Auf diese Weise wird das Headerspoofing begrenzt, da keine Weiterleitungen von nicht vertrauenswürdigen Proxys akzeptiert werden. Wenn ein unbekannter Proxy erkannt wird, gibt die Protokollierung die Adresse des Proxys an:

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

Im vorherigen Beispiel ist 10.0.0.100 ein Proxyserver. Wenn der Server ein vertrauenswürdiger Proxy ist, fügen Sie die IP-Adresse des Servers KnownProxies (oder ein vertrauenswürdiges Netzwerk KnownNetworks) in Startup.ConfigureServices hinzu. Weitere Informationen finden Sie im Abschnitt Middleware für weitergeleitete Header: Optionen.

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

Wichtig

Erlauben Sie nur vertrauenswürdigen Proxys und Netzwerken die Weiterleitung von Headern. Andernfalls sind Angriffe des Typs IP-Spoofing möglich.

Zusätzliche Ressourcen