Konfigurace ASP.NET Core pro práci s proxy servery a nástroji pro vyrovnávání zatížení

Chris Neschůdně

V doporučené konfiguraci pro ASP.NET Core aplikace hostuje služba IIS/ASP.NET Core Module, Nginx nebo Apache. Proxy servery, nástroje pro vyrovnávání zatížení a další síťová zařízení často před dosažením aplikace zakrýují informace o požadavku:

  • Při přenosu požadavků HTTPS přes protokol HTTP se původní schéma (HTTPS) ztratí a musí se předávat v hlavičce.
  • Vzhledem k tomu, že aplikace obdrží požadavek z proxy serveru, a ne z jeho skutečného zdroje na internetu nebo v podnikové síti, ip adresa původního klienta musí být také předána v hlavičce.

Tyto informace mohou být důležité při zpracování požadavků, například při přesměrování, ověřování, generování propojení, vyhodnocení zásad a geografické polohy klienta.

Předáná záhlaví

Podle konvence předávat informace v hlavičkách PROTOKOLU HTTP.

Hlavička Description
Přeposílání X pro Obsahuje informace o klientovi, který inicioval požadavek, a následných serverech pro v řetězu proxů. Tento parametr může obsahovat IP adresy (a volitelně i čísla portů). V řetězu proxy serverů první parametr označuje klienta, ve kterém byl požadavek proveden jako první. Následují následující identifikátory proxy serveru. Poslední proxy server v řetězci není v seznamu parametrů. IP adresa posledního proxy serveru a volitelně číslo portu jsou k dispozici jako vzdálená IP adresa na přenosové vrstvě.
X-Forwarded-Proto Hodnota schématu původu (HTTP/HTTPS). Hodnota může být také seznam schémat, pokud požadavek prochoval více serverů pro.
X-Forwarded-Host Původní hodnota pole Hlavička hostitele. Obvykle se v hlavičkě Hostitele neupravuje ani prox. V informačním zpravodaji zabezpečení společnosti Microsoft CVE-2018-0787 najdete informace o ohrožení zabezpečení v případě zvýšení oprávnění, které ovlivňuje systémy, ve kterých proxy server neověřuje ani neomezuje hlavičky hostitele na známé dobré hodnoty.

Middleware forwarded Headers ( ) čte tyto hlavičky a vyplní ForwardedHeadersMiddleware přidružená pole na HttpContext .

Middleware se aktualizuje:

Další informace o předchozím tématu najdete v tomto GitHub .

Je možné nakonfigurovat výchozí nastavení middlewaru forwarded headers. Výchozí nastavení:

  • Mezi aplikací a zdrojem požadavků je pouze jeden proxy server.
  • Pro známé proxy a známé sítě jsou nakonfigurované jenom adresy zpětné smyčky.
  • Předánané hlavičky mají název X-Forwarded-For a X-Forwarded-Proto .
  • Hodnota je , aby bylo možné povolit middleware, je nutné nastavit požadované ForwardedHeaders ForwardedHeaders.None služby předávání.

Ne všechna síťová zařízení přidávají X-Forwarded-For hlavičky a X-Forwarded-Proto bez další konfigurace. Pokud požadavky naximy neobsahují tyto hlavičky, když se dostanou do aplikace, obraťte se na pokyny výrobce zařízení. Pokud zařízení používá jiné názvy hlaviček než a , nastavte možnosti a tak, aby odpovídaly názvům hlaviček X-Forwarded-For X-Forwarded-Proto ForwardedForHeaderName ForwardedProtoHeaderName používaným zařízením. Další informace najdete v tématu Forwarded Headers Middleware options a Configuration for a proxy, který používá různé názvy hlaviček.

Iis/IIS Express a ASP.NET Core Module

Middleware předáovaných hlaviček je ve výchozím nastavení povolený integračním middlewarem služby IIS, pokud je aplikace hostovaná mimo proces za službou IIS a modulem ASP.NET Core Module. Middleware s předanou hlavičkou se aktivuje tak, aby se nejprve spouštěl v kanálu middlewaru s omezenou konfigurací specifickou pro modul ASP.NET Core, a to kvůli obavám ohledně důvěryhodnosti s předanou hlavičkou (například falšování IP adresy). Middleware je nakonfigurovaný tak, aby předal hlavičky a a je X-Forwarded-For omezený na jeden proxy server X-Forwarded-Proto localhost. Pokud se vyžaduje další konfigurace, podívejte se na možnosti middlewaru Předá v hlavičkách.

Další proxy server a nástroje pro vyrovnávání zatížení

Mimo použití integrace služby IIS při hostovánímimo proces není middleware předáných hlaviček ve výchozím nastavení povolený. Aby aplikace zpracuje předáné hlavičky pomocí , musí být povolený middleware s předaly UseForwardedHeaders hlavičkami. Po povolení middlewaru, pokud je pro middleware zadaný parametr no, jsou výchozí ForwardedHeadersOptions forwardedHeadersOptions.ForwardedHeaders ForwardedHeaders.None.

Nakonfigurujte middleware pomocí ForwardedHeadersOptions , aby předá X-Forwarded-For hlavičky a X-Forwarded-Proto v souboru Startup.ConfigureServices .

Pořadí middlewaru předáovaných hlaviček

Předaný middleware hlaviček by měl být spuštěn před jiným middlewarem. Toto řazení zajišťuje, že middleware, který spoléhá na informace předáných hlaviček, může ke zpracování využívat hodnoty hlaviček. Middleware s předaly hlavičky se může spustit po diagnostice a zpracování chyb, ale před voláním se musí spustit 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?}");
        });
    }
}

Případně před UseForwardedHeaders diagnostikou zavolejte :

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

Poznámka

Pokud ne jsou zadány v nebo přímo na rozšiřující metodu s , výchozí hlavičky k předání ForwardedHeadersOptions Startup.ConfigureServices jsou UseForwardedHeaders ForwardedHeaders.None. Vlastnost ForwardedHeaders musí být nakonfigurovaná s hlavičkami, které se mají předat dál.

Konfigurace serveru Nginx

Pokud chcete X-Forwarded-For hlavičky a předat X-Forwarded-Proto dál, podívejte se na . Hostování ASP.NET Core v Linuxu se serverem Nginx Další informace najdete v tématu NGINX: Použití hlavičky Forwarded.

Konfigurace Apache

X-Forwarded-For se přidá automaticky (viz Apache Module mod_proxy: Hlavičky požadavku reverzního proxy serveru). Informace o tom, jak hlavičku X-Forwarded-Proto předat dál, najdete v tématu Hostování ASP.NET Core v Linuxu pomocí Apache .

Možnosti middlewaru předáovaných hlaviček

ForwardedHeadersOptions řídí chování middlewaru předáovaných hlaviček. Následující příklad změní výchozí hodnoty:

  • Omezte počet položek v předáných hlavičkách na 2 .
  • Přidejte známou adresu proxy serveru 127.0.10.1 .
  • Změňte předaný název hlavičky z výchozí hodnoty X-Forwarded-For na 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";
});
Možnost Popis
AllowedHosts Omezí hostitele podle X-Forwarded-Host hlavičky na zadané hodnoty.
  • Hodnoty se porovnávaly pomocí ordinal-ignore-case.
  • Čísla portů musí být vyloučena.
  • Pokud je seznam prázdný, jsou povoleni všichni hostitelé.
  • Zástupný znak nejvyšší úrovně * umožňuje, aby všichni neprázdní hostitelé.
  • Zástupné znaky subdomény jsou povolené, ale neodpovídají kořenové doméně. Například odpovídá *.contoso.com subdoméně, foo.contoso.com ale ne kořenové doméně contoso.com .
  • Názvy hostitelů Unicode jsou povoleny, ale jsou převedeny na punycode pro porovnávání.
  • Adresy IPv6 musí obsahovat ohraničující závorky a musí být v konvenční podobě (například [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789] ). U IPv6 adres není zvláštní případ, kdy by se kontroloval logická rovnost mezi různými formáty a nesnížení kanoniky.
  • Pokud nepovolíte povolené hostitele, může útočníkovi umožnit falšování odkazů generovaných službou.
Výchozí hodnota je prázdná IList<string> hodnota .
ForwardedForHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedForHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-For jinou hlavičku.

Výchozí formát je X-Forwarded-For.
ForwardedHeaders Určuje, které předávání by se mělo zpracovat. Seznam polí, která se vztahují, najdete v výčtu ForwardedHeaders. Typické hodnoty přiřazené k této vlastnosti jsou ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto .

Výchozí hodnota je ForwardedHeaders.None.
ForwardedHostHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedHostHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-Host jinou hlavičku.

Výchozí formát je X-Forwarded-Host.
ForwardedProtoHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedProtoHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-Proto jinou hlavičku.

Výchozí formát je X-Forwarded-Proto.
ForwardLimit Omezuje počet položek v záhlavích, které jsou zpracovávány. Nastavením null tohoto omezení zakážete, ale to by mělo být provedeno pouze v případě, že KnownProxies nebo KnownNetworks jsou nakonfigurovány. Nastavení null nehodnoty je preventivní opatrnost (ale ne záruka) pro ochranu proti nesprávně konfigurovaným proxy a škodlivým požadavkům přicházejících ze dvoustranných kanálů v síti.

Middleware předávaných hlaviček zpracovává hlavičky v obráceném pořadí zprava doleva. Pokud je použita výchozí hodnota ( 1 ), bude zpracována pouze hodnota zprava z hlaviček, pokud hodnota ForwardLimit není zvýšena.

Výchozí formát je 1.
KnownNetworks Rozsahy adres známých sítí, ze kterých se mají přijímat předávací hlavičky. zadejte rozsahy IP adres pomocí technologie CIDR (Classless Interdomain Routing) (CIDR) notation.

Pokud server používá sokety s duálním režimem, adresy IPv4 jsou zadány ve formátu IPv6 (například 10.0.0.1 v protokolu IPv4 reprezentovaném v protokolu IPv6 jako ::ffff:10.0.0.1 ). Viz IPAddress. MapToIPv6. V části HttpContext. Connection. RemoteIpAddressZjistěte, jestli je tento formát vyžadován.

Výchozí hodnota je IList <IPNetwork> obsahující jednu položku pro IPAddress.Loopback .
KnownProxies Adresy známých proxy adres, ze kterých se mají přijímat předávací hlavičky. Použijte KnownProxies k určení přesné shody IP adres.

Pokud server používá sokety s duálním režimem, adresy IPv4 jsou zadány ve formátu IPv6 (například 10.0.0.1 v protokolu IPv4 reprezentovaném v protokolu IPv6 jako ::ffff:10.0.0.1 ). Viz IPAddress. MapToIPv6. V části HttpContext. Connection. RemoteIpAddressZjistěte, jestli je tento formát vyžadován.

Výchozí hodnota je IList <IPAddress> obsahující jednu položku pro IPAddress.IPv6Loopback .
OriginalForHeaderName Použijte hlavičku určenou touto vlastností místo od ta, kterou Určuje ForwardedHeadersDefaults. XOriginalForHeaderName.

Výchozí formát je X-Original-For.
OriginalHostHeaderName Použijte hlavičku určenou touto vlastností místo od ta, kterou Určuje ForwardedHeadersDefaults. XOriginalHostHeaderName.

Výchozí formát je X-Original-Host.
OriginalProtoHeaderName Použijte hlavičku určenou touto vlastností místo od ta, kterou Určuje ForwardedHeadersDefaults. XOriginalProtoHeaderName.

Výchozí formát je X-Original-Proto.
RequireHeaderSymmetry Vyžaduje, aby byl počet synchronizovaných hodnot hlaviček mezi zpracovávaným ForwardedHeadersOptions. ForwardedHeaders .

výchozí hodnota v ASP.NET Core 1. x je true . výchozí hodnota v ASP.NET Core 2,0 nebo novější je false .

Scénáře a případy použití

Pokud není možné přidat předávané hlavičky a všechny požadavky jsou zabezpečené

V některých případech nemusí být možné přidat předávaná záhlaví do požadavků, které jsou proxy k aplikaci. Pokud proxy vynucuje, že všechny veřejné externí požadavky jsou HTTPS, můžete schéma ručně nastavit v části Startup.Configure před použitím libovolného typu middlewaru:

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

Tento kód může být zakázán pomocí proměnné prostředí nebo jiného nastavení konfigurace ve vývojovém nebo přípravném prostředí.

Práce se základními a proxy servery, které mění cestu požadavku

Některé proxy servery předávají cestu beze změny, ale se základní cestou aplikace, která by se měla odebrat, aby směrování fungovalo správně. Middleware UsePathBaseExtensions. UsePathBase middleware rozdělí cestu do HttpRequest. cesta a základní cestu aplikace do HttpRequest. PathBase.

Pokud /foo je základní cesta aplikace pro cestu k proxy serveru předaná jako /foo/api/1 , middleware nastaví Request.PathBase na /foo a Request.Path do /api/1 pomocí následujícího příkazu:

app.UsePathBase("/foo");

Původní cesta a základ cesty se znovu aplikují, když se middleware znovu zavolá v opačném případě. Další informace o zpracování pořadí middlewaru najdete v tématu ASP.NET Core Jiné .

Pokud proxy ořízne cestu (například předávání /foo/api/1 na /api/1 ), opravte přesměrování a odkazy nastavením vlastnosti PathBase žádosti:

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

Pokud proxy přidává data cest, zahodí část cesty pro opravu přesměrování a odkazy pomocí StartsWithSegments a přiřazení k Path vlastnosti:

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

    return next();
});

Konfigurace proxy serveru, který používá jiné názvy hlaviček

Pokud proxy nepoužívá hlavičky s názvem X-Forwarded-For a X-Forwarded-Proto k přeposlání informací o adrese proxy/portu a informace o původním schématu, ForwardedForHeaderName nastavte ForwardedProtoHeaderName Možnosti a tak, aby odpovídaly názvům hlaviček používaným proxy serverem:

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

Předejte schéma pro reverzní proxy servery se systémy Linux a non-IIS.

Aplikace, které volají UseHttpsRedirection a UseHsts umísťují lokalitu do nekonečné smyčky, pokud jsou nasazené do azure Linux App Service, virtuální počítač Azure Linux (VM) nebo za jakýkoli jiný reverzní proxy server, kromě služby IIS. Protokol TLS je ukončen reverzním proxy serverem a Kestrel nemá na paměti správné schéma požadavků. OAuth a OIDC v této konfiguraci selže, protože generují nesprávná přesměrování. UseIISIntegration Přidá a nakonfiguruje middleware předávaných hlaviček při spuštění za IIS, ale neexistuje žádná vyhovující Automatická konfigurace pro Linux (integrace Apache nebo Nginx).

Pro přeposílání schématu od proxy serveru ve scénářích mimo službu IIS přidejte a nakonfigurujte middleware s předanými hlavičkami. V Startup.ConfigureServices použijte následující kód:

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

Předávání certifikátů

Azure

Pokud chcete nakonfigurovat Azure App Service pro předávání certifikátů, přečtěte si téma Konfigurace vzájemného ověřování TLS pro Azure App Service. následující pokyny se týkají konfigurace aplikace ASP.NET Core.

V Startup.Configure přidejte následující kód před volání do app.UseAuthentication(); :

app.UseCertificateForwarding();

Nakonfigurujte middleware předávání certifikátů a určete název hlavičky, kterou používá Azure. V Startup.ConfigureServices přidejte následující kód pro konfiguraci hlavičky, ze které middleware vytváří certifikát:

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

Další webové proxy servery

Pokud se používá proxy server, který není službou IIS nebo Azure App Service směrování žádostí na aplikace (ARR), nakonfigurujte proxy server tak, aby předal certifikát, který přijal v hlavičce protokolu HTTP. V Startup.Configure přidejte následující kód před volání do app.UseAuthentication(); :

app.UseCertificateForwarding();

Nakonfigurujte middleware předávání certifikátů a zadejte název záhlaví. V Startup.ConfigureServices přidejte následující kód pro konfiguraci hlavičky, ze které middleware vytváří certifikát:

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

Pokud proxy server nemá kódování Base64 (jako je případ s Nginx), nastavte HeaderConverter možnost. Vezměte v úvahu následující příklad 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;
    }
});

Řešení potíží

Když hlavičky nejsou předávány podle očekávání, povolte protokolování. Pokud protokoly neposkytují dostatek informací pro řešení tohoto problému, vytvořte výčet hlaviček požadavků přijatých serverem. K zápisu hlaviček požadavků do odpovědi aplikace nebo k protokolování hlaviček použijte vložený middlewarový middleware.

Chcete-li zapsat hlavičky do odpovědi aplikace, umístěte následující vložený middleware terminálu hned po volání do UseForwardedHeaders 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}");
});

Do protokolů můžete zapisovat místo těla odpovědi. Zápis do protokolů umožňuje, aby lokalita fungovala normálně během ladění.

Zápis protokolů místo textu odpovědi:

app.Use(async (context, next) =>
{
    // Request method, scheme, and path
    _logger.LogDebug("Request Method: {Method}", context.Request.Method);
    _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
    _logger.LogDebug("Request Path: {Path}", context.Request.Path);

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

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

    await next();
});

Při zpracování X-Forwarded-{For|Proto|Host} jsou hodnoty přesunuty na X-Original-{For|Proto|Host} . Pokud existuje více hodnot v dané hlavičce, middleware pro přesměrované hlavičky zpracovává záhlaví v opačném pořadí zprava doleva. Výchozí hodnota ForwardLimit je 1 (jedna), takže je zpracována pouze hodnota zprava z hlaviček, pokud hodnota ForwardLimit není zvýšena.

Původní Vzdálená IP adresa žádosti se musí shodovat s položkou v KnownProxies KnownNetworks seznamech nebo před zpracováním předávaných hlaviček. To omezuje falšování hlaviček tím, že nepřijímá předávací servery od nedůvěryhodných proxy serverů. Při zjištění neznámého proxy serveru se zobrazí zpráva s informacemi o adrese proxy serveru:

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

V předchozím příkladu je 10.0.0.100 proxy server. Pokud je server důvěryhodným proxy serverem, přidejte IP adresu serveru do KnownProxies (nebo přidejte důvěryhodnou síť do KnownNetworks ) v Startup.ConfigureServices . Další informace najdete v části Možnosti middlewaru předávaných hlaviček .

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

Důležité

Povoluje pouze důvěryhodné proxy servery a sítě pro přeposílání hlaviček. V opačném případě jsou možné útoky s falešnou IP adresou .

Další zdroje informací

v doporučené konfiguraci pro ASP.NET Core se aplikace hostuje pomocí modulu IIS/ASP.NET Core, Nginx nebo Apache. Proxy servery, nástroje pro vyrovnávání zatížení a další síťová zařízení často překrývají informace o žádosti předtím, než dosáhnou aplikace:

  • Pokud jsou požadavky HTTPS proxy serverem přes HTTP, původní schéma (HTTPS) se ztratí a musí se přenášet v hlavičce.
  • Vzhledem k tomu, že aplikace obdrží požadavek od proxy serveru a ne jeho skutečný zdroj v Internetu nebo podnikové síti, musí být zdrojová adresa IP klienta předána také v hlavičce.

Tyto informace můžou být důležité ve zpracování žádostí, například v přesměrování, ověřování, generování odkazů, vyhodnocení zásad a geografická poloha klienta.

Předávaná záhlaví

Podle konvence proxy předávají informace v hlavičkách protokolu HTTP.

Hlavička Description
X-předané – pro Uchovává informace o klientovi, který inicioval požadavek a následné proxy servery v řetězci proxy serverů. Tento parametr může obsahovat IP adresy (a volitelně také čísla portů). V řetězci proxy serverů označuje první parametr klienta, ve kterém se žádost poprvé nastavila. Následují následující identifikátory proxy serveru. Poslední proxy server v řetězci není v seznamu parametrů. IP adresa posledního proxy serveru a volitelně číslo portu jsou k dispozici jako vzdálená IP adresa na přenosové vrstvě.
X-Forwarded-Proto Hodnota schématu původu (HTTP/HTTPS). Hodnota může být také seznam schémat, pokud požadavek prochoval více serverů pro.
X-Forwarded-Host Původní hodnota pole Hlavička hostitele. Obvykle se v hlavičkě Hostitele neupravuje ani prox. V informačním zpravodaji zabezpečení společnosti Microsoft CVE-2018-0787 najdete informace o ohrožení zabezpečení z pohledu zvýšení oprávnění, které ovlivňuje systémy, ve kterých proxy server neověřuje ani neomezuje hlavičky hostitele na známé dobré hodnoty.

Middleware Forwarded Headers z balíčku Microsoft.AspNetCore.HttpOverrides tyto hlavičky přečte a vyplní přidružená pole v HttpContext souboru .

Middleware se aktualizuje:

Je možné nakonfigurovat výchozí nastavení middlewaru Forwarded Headers. Výchozí nastavení:

  • Mezi aplikací a zdrojem požadavků je pouze jeden proxy server.
  • Pro známé proxy a známé sítě jsou nakonfigurované jenom adresy zpětné smyčky.
  • Předánané hlavičky mají název X-Forwarded-For a X-Forwarded-Proto .

Ne všechna síťová zařízení přidávají X-Forwarded-For hlavičky a X-Forwarded-Proto bez další konfigurace. Pokud požadavky naximy neobsahují tyto hlavičky, když se dostanou do aplikace, obraťte se na pokyny výrobce zařízení. Pokud zařízení používá jiné názvy hlaviček než a , nastavte možnosti a tak, aby odpovídaly názvům hlaviček X-Forwarded-For X-Forwarded-Proto ForwardedForHeaderName ForwardedProtoHeaderName používaným zařízením. Další informace najdete v tématu Forwarded Headers Middleware options a Configuration for a proxy, který používá různé názvy hlaviček.

Iis/IIS Express a ASP.NET Core Module

Middleware předáovaných hlaviček je ve výchozím nastavení povolený integračním middlewarem služby IIS, pokud je aplikace hostovaná mimo proces za službou IIS a modulem ASP.NET Core Module. Middleware s předanou hlavičkou je aktivovaný tak, aby se nejprve spouštěl v kanálu middlewaru s omezenou konfigurací specifickou pro modul ASP.NET Core, a to kvůli obavám ohledně důvěryhodnosti s předanou hlavičkou (například falšování IP adresy). Middleware je nakonfigurovaný tak, aby předal hlavičky a a je X-Forwarded-For omezený na jeden proxy server X-Forwarded-Proto localhost. Pokud je vyžadována další konfigurace, podívejte se na možnosti middlewaru Předá v hlavičkách.

Další proxy server a nástroje pro vyrovnávání zatížení

Mimo použití integrace služby IIS při hostovánímimo proces není middleware předáných hlaviček ve výchozím nastavení povolený. Aby aplikace zpracuje předáné hlavičky pomocí , musí být povolený middleware s předaly UseForwardedHeaders hlavičkami. Po povolení middlewaru, pokud je pro middleware zadaný parametr no, jsou výchozí ForwardedHeadersOptions forwardedHeadersOptions.ForwardedHeaders ForwardedHeaders.None.

Nakonfigurujte middleware pomocí ForwardedHeadersOptions , aby předá X-Forwarded-For hlavičky a X-Forwarded-Proto v souboru Startup.ConfigureServices . Před UseForwardedHeaders voláním jiného Startup.Configure middlewaru vyvolte metodu v souboru :

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = 
            ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseForwardedHeaders();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    // In ASP.NET Core 1.x, replace the following line with: app.UseIdentity();
    app.UseAuthentication();
    app.UseMvc();
}

Poznámka

Pokud ne jsou zadány v nebo přímo na rozšiřující metodu s , výchozí hlavičky k předání ForwardedHeadersOptions Startup.ConfigureServices jsou UseForwardedHeaders ForwardedHeaders.None. Vlastnost ForwardedHeaders musí být nakonfigurovaná s hlavičkami, které se mají předat dál.

Konfigurace serveru Nginx

Pokud chcete X-Forwarded-For hlavičky a předat X-Forwarded-Proto dál, podívejte se na . Hostování ASP.NET Core v Linuxu se serverem Nginx Další informace najdete v tématu NGINX: Použití hlavičky Forwarded.

Konfigurace Apache

X-Forwarded-For se přidá automaticky (viz Apache Module mod_proxy: Hlavičky požadavku reverzního proxy serveru). Informace o tom, jak hlavičku X-Forwarded-Proto předat dál, najdete v tématu Hostování ASP.NET Core v Linuxu pomocí Apache .

Možnosti middlewaru předáovaných hlaviček

ForwardedHeadersOptions řídí chování middlewaru forwarded headers. Následující příklad změní výchozí hodnoty:

  • Omezte počet položek v předáných hlavičkách na 2 .
  • Přidejte známou adresu proxy serveru 127.0.10.1 .
  • Změňte předaný název hlavičky z výchozí hodnoty X-Forwarded-For na 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";
});
Možnost Popis
AllowedHosts Omezí hostitele podle X-Forwarded-Host hlavičky na zadané hodnoty.
  • Hodnoty se porovnávaly pomocí ordinal-ignore-case.
  • Čísla portů musí být vyloučena.
  • Pokud je seznam prázdný, jsou povoleni všichni hostitelé.
  • Zástupný znak nejvyšší úrovně * umožňuje, aby všichni neprázdní hostitelé.
  • Zástupné znaky subdomény jsou povolené, ale neodpovídají kořenové doméně. Například odpovídá *.contoso.com subdoméně, foo.contoso.com ale ne kořenové doméně contoso.com .
  • Názvy hostitelů Unicode jsou povoleny, ale jsou převedeny na punycode pro porovnávání.
  • Adresy IPv6 musí obsahovat ohraničující závorky a musí být v konvenční podobě (například [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789] ). Adresy IPv6 se neškrtnou zvláštním případem pro kontrolu logické rovnosti mezi různými formáty a není provedena žádná kanonizace.
  • Pokud nepovolíte povolené hostitele, může útočníkovi umožnit falšování odkazů generovaných službou.
Výchozí hodnota je prázdná IList<string> hodnota .
ForwardedForHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedForHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-For jinou hlavičku.

Výchozí formát je X-Forwarded-For.
ForwardedHeaders Určuje, které předávání by se mělo zpracovat. Seznam polí, která se vztahují, najdete v výčtu ForwardedHeaders. Typické hodnoty přiřazené k této vlastnosti jsou ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto .

Výchozí hodnota je ForwardedHeaders.None.
ForwardedHostHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedHostHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-Host jinou hlavičku.

Výchozí formát je X-Forwarded-Host.
ForwardedProtoHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XForwardedProtoHeaderName. Tato možnost se používá v případě, že proxy server nebo služba předávání hlavičku nevyuží, ale k předávání informací používá X-Forwarded-Proto jinou hlavičku.

Výchozí formát je X-Forwarded-Proto.
ForwardLimit Omezuje počet položek v hlavičkách, které jsou zpracovány. Nastavte null na , pokud chcete limit zakázat, ale mělo by se to provést jenom v případě, že jsou KnownProxies KnownNetworks nakonfigurované nebo . Nastavení hodnoty, která není hodnotou, je preventivní opatření (ale nikoli záruka), které je třeba chránit před chybně nakonfigurovaným serverem prox a škodlivými požadavky přicházející z postranních null kanálů v síti.

Middleware s předaly hlavičky zpracovává hlavičky v obráceném pořadí zprava doleva. Pokud se použije výchozí hodnota ( ), zpracuje se pouze hodnota z hlaviček nejvíce vpravo, pokud se 1 ForwardLimit hodnota nezvýší.

Výchozí formát je 1.
KnownNetworks Rozsahy adres známých sítí, ze které se přijímou předáné hlavičky. Zadejte rozsahy IP adres pomocí technologie CIDR (Classless Interdomain Routing) (CIDR).

Pokud server používá sokety s duálním režimem, adresy IPv4 se zadávají ve formátu IPv6 (například v IPv4 reprezentované 10.0.0.1 v IPv6 jako ::ffff:10.0.0.1 ). Viz IPAddress.MapToIPv6. Zjistěte, jestli se tento formát vyžaduje, v httpcontext.connection.remoteipaddress. Další informace najdete v části Konfigurace pro adresu IPv4 reprezentované jako adresa IPv6.

Výchozí hodnota je> IList <IPNetwork obsahující jednu položku pro IPAddress.Loopback .
KnownProxies Adresy známých proxy serverů pro příjem předáných hlaviček. Pomocí KnownProxies můžete zadat přesné shody IP adres.

Pokud server používá sokety s duálním režimem, adresy IPv4 se zadávají ve formátu IPv6 (například v IPv4 reprezentované 10.0.0.1 v IPv6 jako ::ffff:10.0.0.1 ). Viz IPAddress.MapToIPv6. Zjistěte, jestli se tento formát vyžaduje, v httpcontext.connection.remoteipaddress. Další informace najdete v části Konfigurace pro adresu IPv4 reprezentované jako adresa IPv6.

Výchozí hodnota je> IList <IPAddress obsahující jednu položku pro IPAddress.IPv6Loopback .
OriginalForHeaderName Použijte hlavičku určenou touto vlastností místo hlavičky určené parametrem ForwardedHeadersDefaults.XOriginalForHeaderName.

Výchozí formát je X-Original-For.
OriginalHostHeaderName Použijte hlavičku určenou touto vlastností místo od ta, kterou Určuje ForwardedHeadersDefaults. XOriginalHostHeaderName.

Výchozí formát je X-Original-Host.
OriginalProtoHeaderName Použijte hlavičku určenou touto vlastností místo od ta, kterou Určuje ForwardedHeadersDefaults. XOriginalProtoHeaderName.

Výchozí formát je X-Original-Proto.
RequireHeaderSymmetry Vyžaduje, aby byl počet synchronizovaných hodnot hlaviček mezi zpracovávaným ForwardedHeadersOptions. ForwardedHeaders .

výchozí hodnota v ASP.NET Core 1. x je true . výchozí hodnota v ASP.NET Core 2,0 nebo novější je false .

Scénáře a případy použití

Pokud není možné přidat předávané hlavičky a všechny požadavky jsou zabezpečené

V některých případech nemusí být možné přidat předávaná záhlaví do požadavků, které jsou proxy k aplikaci. Pokud proxy vynucuje, že všechny veřejné externí požadavky jsou HTTPS, můžete schéma ručně nastavit v části Startup.Configure před použitím libovolného typu middlewaru:

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

Tento kód může být zakázán pomocí proměnné prostředí nebo jiného nastavení konfigurace ve vývojovém nebo přípravném prostředí.

Práce se základními a proxy servery, které mění cestu požadavku

Některé proxy servery předávají cestu beze změny, ale se základní cestou aplikace, která by se měla odebrat, aby směrování fungovalo správně. Middleware UsePathBaseExtensions. UsePathBase middleware rozdělí cestu do HttpRequest. cesta a základní cestu aplikace do HttpRequest. PathBase.

Pokud /foo je základní cesta aplikace pro cestu k proxy serveru předaná jako /foo/api/1 , middleware nastaví Request.PathBase na /foo a Request.Path do /api/1 pomocí následujícího příkazu:

app.UsePathBase("/foo");

Původní cesta a základ cesty se znovu aplikují, když se middleware znovu zavolá v opačném případě. Další informace o zpracování pořadí middlewaru najdete v tématu ASP.NET Core Jiné .

Pokud proxy ořízne cestu (například předávání /foo/api/1 na /api/1 ), opravte přesměrování a odkazy nastavením vlastnosti PathBase žádosti:

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

Pokud proxy přidává data cest, zahodí část cesty pro opravu přesměrování a odkazy pomocí StartsWithSegments a přiřazení k Path vlastnosti:

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

    return next();
});

Konfigurace proxy serveru, který používá jiné názvy hlaviček

Pokud proxy nepoužívá hlavičky s názvem X-Forwarded-For a X-Forwarded-Proto k přeposlání informací o adrese proxy/portu a informace o původním schématu, ForwardedForHeaderName nastavte ForwardedProtoHeaderName Možnosti a tak, aby odpovídaly názvům hlaviček používaným proxy serverem:

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

Konfigurace pro adresu IPv4 reprezentovanou jako IPv6 adresa

Pokud server používá sokety s duálním režimem, adresy IPv4 jsou zadány ve formátu IPv6 (například 10.0.0.1 v protokolu IPv4 reprezentovaného v protokolu IPv6 jako ::ffff:10.0.0.1 nebo ::ffff:a00:1 ). Viz IPAddress. MapToIPv6. V části HttpContext. Connection. RemoteIpAddressZjistěte, jestli je tento formát vyžadován.

V následujícím příkladu se síťová adresa, která poskytuje předávaná záhlaví, přidá do KnownNetworks seznamu ve formátu protokolu IPv6.

Adresa IPv4: 10.11.12.1/8

Převedená adresa IPv6: ::ffff:10.11.12.1
Délka převedené předpony: 104

Adresu můžete také uvést v šestnáctkovém formátu ( 10.11.12.1 reprezentované protokolem IPv6 jako ::ffff:0a0b:0c01 ). Při převodu adresy IPv4 na IPv6 přidejte 96 k délce předpony CIDR ( 8 v příkladu), aby se zohlednila další ::ffff: předpona IPv6 (8 + 96 = 104).

// To access IPNetwork and IPAddress, add the following namespaces:
// using System.Net;
// using Microsoft.AspNetCore.HttpOverrides;
services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.KnownNetworks.Add(new IPNetwork(
        IPAddress.Parse("::ffff:10.11.12.1"), 104));
});

Předejte schéma pro reverzní proxy servery se systémy Linux a non-IIS.

Aplikace, které volají UseHttpsRedirection a UseHsts umísťují lokalitu do nekonečné smyčky, pokud jsou nasazené do azure Linux App Service, virtuální počítač Azure Linux (VM) nebo za jakýkoli jiný reverzní proxy server, kromě služby IIS. Protokol TLS je ukončen reverzním proxy serverem a Kestrel nemá na paměti správné schéma požadavků. OAuth a OIDC v této konfiguraci selže, protože generují nesprávná přesměrování. UseIISIntegration Přidá a nakonfiguruje middleware předávaných hlaviček při spuštění za IIS, ale neexistuje žádná vyhovující Automatická konfigurace pro Linux (integrace Apache nebo Nginx).

Pro přeposílání schématu od proxy serveru ve scénářích mimo službu IIS přidejte a nakonfigurujte middleware s předanými hlavičkami. V Startup.ConfigureServices použijte následující kód:

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

Řešení potíží

Když hlavičky nejsou předávány podle očekávání, povolte protokolování. Pokud protokoly neposkytují dostatek informací pro řešení tohoto problému, vytvořte výčet hlaviček požadavků přijatých serverem. K zápisu hlaviček požadavků do odpovědi aplikace nebo k protokolování hlaviček použijte vložený middlewarový middleware.

Chcete-li zapsat hlavičky do odpovědi aplikace, umístěte následující vložený middleware terminálu hned po volání do UseForwardedHeaders 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}");
});

Do protokolů můžete zapisovat místo těla odpovědi. Zápis do protokolů umožňuje, aby lokalita fungovala normálně během ladění.

Zápis protokolů místo textu odpovědi:

app.Use(async (context, next) =>
{
    // Request method, scheme, and path
    _logger.LogDebug("Request Method: {Method}", context.Request.Method);
    _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
    _logger.LogDebug("Request Path: {Path}", context.Request.Path);

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

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

    await next();
});

Při zpracování X-Forwarded-{For|Proto|Host} jsou hodnoty přesunuty na X-Original-{For|Proto|Host} . Pokud existuje více hodnot v dané hlavičce, middleware pro přesměrované hlavičky zpracovává záhlaví v opačném pořadí zprava doleva. Výchozí hodnota ForwardLimit je 1 (jedna), takže je zpracována pouze hodnota zprava z hlaviček, pokud hodnota ForwardLimit není zvýšena.

Původní Vzdálená IP adresa žádosti se musí shodovat s položkou v KnownProxies KnownNetworks seznamech nebo před zpracováním předávaných hlaviček. To omezuje falšování hlaviček tím, že nepřijímá předávací servery od nedůvěryhodných proxy serverů. Při zjištění neznámého proxy serveru se zobrazí zpráva s informacemi o adrese proxy serveru:

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

V předchozím příkladu je 10.0.0.100 proxy server. Pokud je server důvěryhodným proxy serverem, přidejte IP adresu serveru do KnownProxies (nebo přidejte důvěryhodnou síť do KnownNetworks ) v Startup.ConfigureServices . Další informace najdete v části Možnosti middlewaru předávaných hlaviček .

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

Důležité

Povoluje pouze důvěryhodné proxy servery a sítě pro přeposílání hlaviček. V opačném případě jsou možné útoky s falešnou IP adresou .

Další zdroje informací