設定 ASP.NET Core 以與 Proxy 伺服器和負載平衡器搭配運作Configure ASP.NET Core to work with proxy servers and load balancers

作者:Luke LathamChris RossBy Luke Latham and Chris Ross

在建議的 ASP.NET Core 設定中,是使用 IIS/ASP.NET Core 模組、Nginx 或 Apache 來裝載應用程式。In the recommended configuration for ASP.NET Core, the app is hosted using IIS/ASP.NET Core Module, Nginx, or Apache. Proxy 伺服器、負載平衡器及其他網路設備通常會在要求觸達應用程式之前,遮蔽要求的相關資訊:Proxy servers, load balancers, and other network appliances often obscure information about the request before it reaches the app:

  • 透過 HTTP 作為 Proxy 來處理 HTTPS 要求時,原始配置 (HTTPS) 會遺失而必須在標頭中轉送。When HTTPS requests are proxied over HTTP, the original scheme (HTTPS) is lost and must be forwarded in a header.
  • 由於應用程式會從 Proxy 而不是從網際網路或公司網路上的真實來源收到要求,因此必須也在標頭中轉送原始用戶端 IP 位址。Because an app receives a request from the proxy and not its true source on the Internet or corporate network, the originating client IP address must also be forwarded in a header.

此資訊在要求處理方面可能相當重要,例如在重新導向、驗證、連結產生、原則評估及用戶端地理位置方面。This information may be important in request processing, for example in redirects, authentication, link generation, policy evaluation, and client geolocation.

轉送的標頭Forwarded headers

依照慣例,Proxy 會以 HTTP 標頭轉送資訊。By convention, proxies forward information in HTTP headers.

頁首Header 說明Description
X-Forwarded-ForX-Forwarded-For 針對在 Proxy 鏈結中起始要求及後續 Proxy 的用戶端,保存用戶端的相關資訊。Holds information about the client that initiated the request and subsequent proxies in a chain of proxies. 此參數可能包含 IP 位址 (以及視需要可能會有連接埠號碼)。This parameter may contain IP addresses (and, optionally, port numbers). 在 Proxy 伺服器鏈結中,第一個參數會指出起始要求的用戶端。In a chain of proxy servers, the first parameter indicates the client where the request was first made. 後面接著後續的 Proxy 識別碼。Subsequent proxy identifiers follow. 鏈結中的最後一個 Proxy 並不在參數清單中。The last proxy in the chain isn't in the list of parameters. 最後一個 Proxy 的 IP 位址 (以及視需要會有連接埠號碼) 會在傳輸層以遠端 IP 位址的形式提供。The last proxy's IP address, and optionally a port number, are available as the remote IP address at the transport layer.
X-Forwarded-ProtoX-Forwarded-Proto 原始配置的值 (HTTP/HTTPS)。The value of the originating scheme (HTTP/HTTPS). 如果要求周遊了多個 Proxy,則此值也可能是一個配置清單。The value may also be a list of schemes if the request has traversed multiple proxies.
X-Forwarded-HostX-Forwarded-Host 主機標頭欄位的原始值。The original value of the Host header field. 通常,Proxy 不會修改主機標頭。Usually, proxies don't modify the Host header. 如需有關權限提高弱點的資訊,請參閱 Microsoft 資訊安全諮詢 CVE-2018-0787 (英文),此弱點會影響 Proxy 不會驗證或限制主機標頭為已知有效值的系統。See Microsoft Security Advisory CVE-2018-0787 for information on an elevation-of-privileges vulnerability that affects systems where the proxy doesn't validate or restrict Host headers to known good values.

來自 Microsoft.AspNetCore.HttpOverrides 套件的「轉送的標頭中介軟體」會讀取這些標頭,並填入 HttpContext 上相關聯的欄位。The Forwarded Headers Middleware, from the Microsoft.AspNetCore.HttpOverrides package, reads these headers and fills in the associated fields on HttpContext.

中介軟體會更新:The middleware updates:

您可以設定「轉送的標頭中介軟體」的預設設定Forwarded Headers Middleware default settings can be configured. 預設設定包括:The default settings are:

  • 在應用程式與要求的來源之間只有「一個 Proxy」 。There is only one proxy between the app and the source of the requests.
  • 針對已知的 Proxy 和已知的網路,只會設定回送位址。Only loopback addresses are configured for known proxies and known networks.
  • 轉送標頭名稱為 X-Forwarded-ForX-Forwarded-ProtoThe forwarded headers are named X-Forwarded-For and X-Forwarded-Proto.

並非所有網路設備在新增 X-Forwarded-ForX-Forwarded-Proto 標頭時都不含額外組態。Not all network appliances add the X-Forwarded-For and X-Forwarded-Proto headers without additional configuration. 如果透過 Proxy 傳送的要求在觸達應用程式時未包含這些標頭,請向您的設備製造商尋求指引。Consult your appliance manufacturer's guidance if proxied requests don't contain these headers when they reach the app. 如果設備使用的名稱不是 X-Forwarded-ForX-Forwarded-Proto,請設定 ForwardedForHeaderNameForwardedProtoHeaderName 選項,以符合設備使用的標頭名稱。If the appliance uses different header names than X-Forwarded-For and X-Forwarded-Proto, set the ForwardedForHeaderName and ForwardedProtoHeaderName options to match the header names used by the appliance. 如需詳細資訊,請參閱轉送標頭中介軟體選項使用不同標頭名稱之 Proxy 的組態For more information, see Forwarded Headers Middleware options and Configuration for a proxy that uses different header names.

IIS/IIS Express 和 ASP.NET Core 模組IIS/IIS Express and ASP.NET Core Module

當應用程式是在 IIS 和 ASP.NET Core 模組的後方進行處理序外裝載時,IIS 整合中介軟體預設會啟用「轉送的標頭中介軟體」。Forwarded Headers Middleware is enabled by default by IIS Integration Middleware when the app is hosted out-of-process behind IIS and the ASP.NET Core Module. 由於有與轉送標頭相關的信任考量 (例如 IP 詐騙),因此「轉送的標頭中介軟體」在啟用後會先在中介軟體管線中搭配 ASP.NET Core 模組限定的設定來執行。Forwarded Headers Middleware is activated to run first in the middleware pipeline with a restricted configuration specific to the ASP.NET Core Module due to trust concerns with forwarded headers (for example, IP spoofing). 中介軟體會經設定來轉送 X-Forwarded-ForX-Forwarded-Proto 標頭,並限制成單一 localhost Proxy。The middleware is configured to forward the X-Forwarded-For and X-Forwarded-Proto headers and is restricted to a single localhost proxy. 如果需要額外的設定,請參閱轉送的標頭中介軟體選項If additional configuration is required, see the Forwarded Headers Middleware options.

其他 Proxy 伺服器和負載平衡器案例Other proxy server and load balancer scenarios

除了在處理序外裝載時使用 IIS 整合之外,都未預設啟用「轉送的標頭中介軟體」。Outside of using IIS Integration when hosting out-of-process, Forwarded Headers Middleware isn't enabled by default. 必須啟用「轉送的標頭中介軟體」,應用程式才能使用 UseForwardedHeaders 來處理轉送的標頭。Forwarded Headers Middleware must be enabled for an app to process forwarded headers with UseForwardedHeaders. 啟用此中介軟體之後,如果未將任何 ForwardedHeadersOptions 指定給中介軟體,則預設的 ForwardedHeadersOptions.ForwardedHeaders 會是 ForwardedHeaders.NoneAfter enabling the middleware if no ForwardedHeadersOptions are specified to the middleware, the default ForwardedHeadersOptions.ForwardedHeaders are ForwardedHeaders.None.

搭配 ForwardedHeadersOptions 設定中介軟體,以在 Startup.ConfigureServices 中轉送 X-Forwarded-ForX-Forwarded-Proto 標頭。Configure the middleware with ForwardedHeadersOptions to forward the X-Forwarded-For and X-Forwarded-Proto headers in Startup.ConfigureServices. 在呼叫其他中介軟體之前,請先在 Startup.Configure 中叫用 UseForwardedHeaders 方法:Invoke the UseForwardedHeaders method in Startup.Configure before calling other middleware:

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

注意

若未在 Startup.ConfigureServices 中指定 ForwardedHeadersOptions,或未使用 UseForwardedHeaders 直接指定到擴充方法,則要轉送的預設標頭是 ForwardedHeaders.NoneIf no ForwardedHeadersOptions are specified in Startup.ConfigureServices or directly to the extension method with UseForwardedHeaders, the default headers to forward are ForwardedHeaders.None. 必須使用要轉送的標頭設定 ForwardedHeaders 屬性。The ForwardedHeaders property must be configured with the headers to forward.

Nginx 組態Nginx configuration

若要轉送 X-Forwarded-ForX-Forwarded-Proto 標頭,請參閱 在 Linux 上使用 Nginx 裝載 ASP.NET CoreTo forward the X-Forwarded-For and X-Forwarded-Proto headers, see 在 Linux 上使用 Nginx 裝載 ASP.NET Core. 如需詳細資訊,請參閱 NGINX:使用轉送的標頭 (英文)。For more information, see NGINX: Using the Forwarded header.

Apache 組態Apache configuration

X-Forwarded-For 會自動新增 (請參閱 Apache 模組 mod_proxy:反向 Proxy 要求標頭 (英文))。X-Forwarded-For is added automatically (see Apache Module mod_proxy: Reverse Proxy Request Headers). 如需如何轉送 X-Forwarded-Proto 標頭的資訊,請參閱 在 Linux 上使用 Apache 裝載 ASP.NET CoreFor information on how to forward the X-Forwarded-Proto header, see 在 Linux 上使用 Apache 裝載 ASP.NET Core.

轉送的標頭中介軟體選項Forwarded Headers Middleware options

ForwardedHeadersOptions 會控制轉送標頭中介軟體的行為。ForwardedHeadersOptions control the behavior of the Forwarded Headers Middleware. 下列範例會變更預設值:The following example changes the default values:

  • 將轉送標頭中的項目數限制為 2Limit the number of entries in the forwarded headers to 2.
  • 新增已知的 Proxy 位址 127.0.10.1Add a known proxy address of 127.0.10.1.
  • 將轉送標頭名稱從預設的 X-Forwarded-For 變更為 X-Forwarded-For-My-Custom-Header-NameChange the forwarded header name from the default X-Forwarded-For to 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 說明Description
AllowedHostsAllowedHosts 依據 X-Forwarded-Host 標頭將主機限制成所提供的值。Restricts hosts by the X-Forwarded-Host header to the values provided.
  • 比較值時,會使用序數忽略大小寫的方式來比較。Values are compared using ordinal-ignore-case.
  • 必須排除連接埠號碼。Port numbers must be excluded.
  • 如果清單空白,即表示允許所有主機。If the list is empty, all hosts are allowed.
  • 最上層的萬用字元 * 代表會允許所有非空白的主機。A top-level wildcard * allows all non-empty hosts.
  • 允許使用子網域萬用字元,但不會比對出根網域。Subdomain wildcards are permitted but don't match the root domain. 例如,*.contoso.com 會比對出子網域 foo.contoso.com,但不會比對出根網域 contoso.comFor example, *.contoso.com matches the subdomain foo.contoso.com but not the root domain contoso.com.
  • 允許使用 Unicode 主機名稱,但會轉換成 Punycode 來進行比對。Unicode host names are allowed but are converted to Punycode for matching.
  • IPv6 addresses 必須包含週框方括號,並採用慣例格式 (例如 [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789])。IPv6 addresses must include bounding brackets and be in conventional form (for example, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). IPv6 位址並未特別設計成會檢查不同格式間是否具有邏輯相等性,因此不會執行標準化。IPv6 addresses aren't special-cased to check for logical equality between different formats, and no canonicalization is performed.
  • 如果無法限制可允許的主機,可能會讓攻擊者偽造服務所產生的連結。Failure to restrict the allowed hosts may allow an attacker to spoof links generated by the service.
預設值是空的 IList<string>The default value is an empty IList<string>.
ForwardedForHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XForwardedForHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XForwardedForHeaderName. 當 Proxy/轉寄站未使用 X-Forwarded-For 標頭,而使用其他標頭轉送資訊時,會使用此選項。This option is used when the proxy/forwarder doesn't use the X-Forwarded-For header but uses some other header to forward the information.

預設為 X-Forwarded-ForThe default is X-Forwarded-For.
ForwardedHeaders 識別應該處理哪個轉送子。Identifies which forwarders should be processed. 如需適用的欄位清單,請參閱 ForwardedHeaders 列舉See the ForwardedHeaders Enum for the list of fields that apply. 指派給此屬性的典型值是 `ForwardedHeaders.XForwardedForTypical values assigned to this property are `ForwardedHeaders.XForwardedFor ForwardedHeaders.XForwardedProto`。ForwardedHeaders.XForwardedProto`.

預設值為 ForwardedHeaders.NoneThe default value is ForwardedHeaders.None.
ForwardedHostHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XForwardedHostHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XForwardedHostHeaderName. 當 Proxy/轉寄站未使用 X-Forwarded-Host 標頭,而使用其他標頭轉送資訊時,會使用此選項。This option is used when the proxy/forwarder doesn't use the X-Forwarded-Host header but uses some other header to forward the information.

預設為 X-Forwarded-HostThe default is X-Forwarded-Host.
ForwardedProtoHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XForwardedProtoHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XForwardedProtoHeaderName. 當 Proxy/轉寄站未使用 X-Forwarded-Proto 標頭,而使用其他標頭轉送資訊時,會使用此選項。This option is used when the proxy/forwarder doesn't use the X-Forwarded-Proto header but uses some other header to forward the information.

預設為 X-Forwarded-ProtoThe default is X-Forwarded-Proto.
ForwardLimit 限制所處理標頭中的項目數。Limits the number of entries in the headers that are processed. 設定為 null 可停用限制,但應該只有在已設定 KnownProxiesKnownNetworks 的情況下,才這樣做。Set to null to disable the limit, but this should only be done if KnownProxies or KnownNetworks are configured.

預設為 1。The default is 1.
KnownNetworks 可從中接受轉送標頭的已知網路位址範圍。Address ranges of known networks to accept forwarded headers from. 請使用無類別網域間路由 (CIDR) 標記法來提供 IP 範圍。Provide IP ranges using Classless Interdomain Routing (CIDR) notation.

若伺服器使用雙模式通訊端,會以 IPv6 格式 (例如,IPv4 中的 10.0.0.1 在 IPv6 中以 ::ffff:10.0.0.1 表示) 提供 IPv4 位址。If the server is using dual-mode sockets, IPv4 addresses are supplied in an IPv6 format (for example, 10.0.0.1 in IPv4 represented in IPv6 as ::ffff:10.0.0.1). 請參閱 IPAddress.MapToIPv6See IPAddress.MapToIPv6. 透過查看 HttpContext.Connection.RemoteIpAddress 以判斷是否需要此格式。Determine if this format is required by looking at the HttpContext.Connection.RemoteIpAddress. 如需詳細資訊,請參閱以 IPv6 位址表示的 IPv4 位址設定一節。For more information, see the Configuration for an IPv4 address represented as an IPv6 address section.

預設值為包含單一 IPAddress.Loopback 項目的 IList<IPNetwork>。The default is an IList<IPNetwork> containing a single entry for IPAddress.Loopback.
KnownProxies 可從中接受轉送標頭的已知 Proxy 位址。Addresses of known proxies to accept forwarded headers from. 請使用 KnownProxies 來指定確切的相符 IP 位址。Use KnownProxies to specify exact IP address matches.

若伺服器使用雙模式通訊端,會以 IPv6 格式 (例如,IPv4 中的 10.0.0.1 在 IPv6 中以 ::ffff:10.0.0.1 表示) 提供 IPv4 位址。If the server is using dual-mode sockets, IPv4 addresses are supplied in an IPv6 format (for example, 10.0.0.1 in IPv4 represented in IPv6 as ::ffff:10.0.0.1). 請參閱 IPAddress.MapToIPv6See IPAddress.MapToIPv6. 透過查看 HttpContext.Connection.RemoteIpAddress 以判斷是否需要此格式。Determine if this format is required by looking at the HttpContext.Connection.RemoteIpAddress. 如需詳細資訊,請參閱以 IPv6 位址表示的 IPv4 位址設定一節。For more information, see the Configuration for an IPv4 address represented as an IPv6 address section.

預設值為包含單一 IPAddress.IPv6Loopback 項目的 IList<IPAddress>。The default is an IList<IPAddress> containing a single entry for IPAddress.IPv6Loopback.
OriginalForHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XOriginalForHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XOriginalForHeaderName.

預設為 X-Original-ForThe default is X-Original-For.
OriginalHostHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XOriginalHostHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XOriginalHostHeaderName.

預設為 X-Original-HostThe default is X-Original-Host.
OriginalProtoHeaderName 使用此屬性所指定的標頭,而不是 ForwardedHeadersDefaults.XOriginalProtoHeaderName 所指定的標頭。Use the header specified by this property instead of the one specified by ForwardedHeadersDefaults.XOriginalProtoHeaderName.

預設為 X-Original-ProtoThe default is X-Original-Proto.
RequireHeaderSymmetry 要求所處理 ForwardedHeadersOptions.ForwardedHeaders 的標頭值數目必須同步。Require the number of header values to be in sync between the ForwardedHeadersOptions.ForwardedHeaders being processed.

ASP.NET Core 1.x 中的預設值為 trueThe default in ASP.NET Core 1.x is true. ASP.NET Core 2.0 或更新版本中的預設值為 falseThe default in ASP.NET Core 2.0 or later is false.

情節和使用案例Scenarios and use cases

當可以新增轉送的標頭且所有要求都安全時When it isn't possible to add forwarded headers and all requests are secure

在某些情況下,可能無法將轉送的標頭新增至透過 Proxy 傳送給應用程式的要求。In some cases, it might not be possible to add forwarded headers to the requests proxied to the app. 如果 Proxy 強制要求所有公用外部要求都必須是 HTTPS,您可以在使用任何類型的中介軟體之前,先手動在 Startup.Configure 中設定該配置:If the proxy is enforcing that all public external requests are HTTPS, the scheme can be manually set in Startup.Configure before using any type of middleware:

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

在開發或預備環境中,可以使用環境變數或其他組態設定來停用此程式碼。This code can be disabled with an environment variable or other configuration setting in a development or staging environment.

處理路徑基底和變更要求路徑的 ProxyDeal with path base and proxies that change the request path

有些 Proxy 會原封不動傳送路徑,但其中含有應移除才能正確路由傳送的應用程式基底路徑。Some proxies pass the path intact but with an app base path that should be removed so that routing works properly. UsePathBaseExtensions.UsePathBase 中介軟體會將該路徑分割成 HttpRequest.Path,以及將應用程式基底路徑分割成 HttpRequest.PathBaseUsePathBaseExtensions.UsePathBase middleware splits the path into HttpRequest.Path and the app base path into HttpRequest.PathBase.

如果 /foo 是以 /foo/api/1 形式傳送之 Proxy 路徑的應用程式基底路徑,中介軟體就會使用下列命令,將 Request.PathBase 設定為 /foo,以及將 Request.Path 設定為 /api/1If /foo is the app base path for a proxy path passed as /foo/api/1, the middleware sets Request.PathBase to /foo and Request.Path to /api/1 with the following command:

app.UsePathBase("/foo");

反向再次呼叫應用程式時,則會重新套用原始路徑和路徑基底。The original path and path base are reapplied when the middleware is called again in reverse. 如需中介軟體順序處理的詳細資訊,請參閱 ASP.NET Core 中介軟體For more information on middleware order processing, see ASP.NET Core 中介軟體.

如果 Proxy 會修剪路徑 (例如,將 /foo/api/1 轉送給 /api/1),請設定要求的 PathBase 屬性來修正重新導向和連結:If the proxy trims the path (for example, forwarding /foo/api/1 to /api/1), fix redirects and links by setting the request's PathBase property:

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

如果 Proxy 會新增路徑資料,請使用 StartsWithSegments 並指派給 Path 屬性,以捨棄部分路徑來修正重新導向和連結:If the proxy is adding path data, discard part of the path to fix redirects and links by using StartsWithSegments and assigning to the Path property:

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

    return next();
});

使用不同標頭名稱之 Proxy 的組態Configuration for a proxy that uses different header names

如果 Proxy 未使用名為 X-Forwarded-ForX-Forwarded-Proto 的標頭轉送 Proxy 位址/連接埠與原始配置資訊,請設定 ForwardedForHeaderNameForwardedProtoHeaderName 選項,以符合 Proxy 使用的標頭名稱:If the proxy doesn't use headers named X-Forwarded-For and X-Forwarded-Proto to forward the proxy address/port and originating scheme information, set the ForwardedForHeaderName and ForwardedProtoHeaderName options to match the header names used by the proxy:

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedForHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-For_Header";
    options.ForwardedProtoHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-Proto_Header";
});

以 IPv6 位址表示的 IPv4 位址設定Configuration for an IPv4 address represented as an IPv6 address

若伺服器使用雙模式通訊端,會以 IPv6 格式 (例如,IPv4 中的 10.0.0.1 在 IPv6 中以 ::ffff:10.0.0.1 表示) 或 ::ffff:a00:1 提供 IPv4 位址。If the server is using dual-mode sockets, IPv4 addresses are supplied in an IPv6 format (for example, 10.0.0.1 in IPv4 represented in IPv6 as ::ffff:10.0.0.1 or ::ffff:a00:1). 請參閱 IPAddress.MapToIPv6See IPAddress.MapToIPv6. 透過查看 HttpContext.Connection.RemoteIpAddress 以判斷是否需要此格式。Determine if this format is required by looking at the HttpContext.Connection.RemoteIpAddress.

在下列範例中,提供轉寄標頭的網路位址已以 IPv6 格式新增到 KnownNetworks 清單中。In the following example, a network address that supplies forwarded headers is added to the KnownNetworks list in IPv6 format.

IPv4 位址:10.11.12.1/8IPv4 address: 10.11.12.1/8

轉換的 IPv6 位址:::ffff:10.11.12.1Converted IPv6 address: ::ffff:10.11.12.1
轉換的首碼長度:104Converted prefix length: 104

您也能以十六進位格式提供位址 (10.11.12.1 在 IPv6 中以 ::ffff:0a0b:0c01 表示)。You can also supply the address in hexadecimal format (10.11.12.1 represented in IPv6 as ::ffff:0a0b:0c01). 當您將 IPv4 位址轉換為 IPv6 時,請加入 96 到 CIDR 首碼長度 (在此範例中為 8) 以將額外的 ::ffff: IPv6 首碼 (8 + 96 = 104) 納入考慮。When converting an IPv4 address to IPv6, add 96 to the CIDR Prefix Length (8 in the example) to account for the additional ::ffff: IPv6 prefix (8 + 96 = 104).

// To access IPNetwork and IPAddress, add the following namespaces:
// using 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));
});

轉送 Linux 和非 IIS 反向 Proxy 的配置Forward the scheme for Linux and non-IIS reverse proxies

.NET Core 範本呼叫 UseHttpsRedirectionUseHsts.NET Core templates call UseHttpsRedirection and UseHsts. 如果部署至 Azure Linux App Service、Azure Linux 虛擬機器 (VM),或 IIS 之外的任何其他反向 Proxy 後端,則這些方法會將站台放入無限迴圈中。These methods put a site into an infinite loop if deployed to an Azure Linux App Service, Azure Linux virtual machine (VM), or behind any other reverse proxy besides IIS. 反向 Proxy 會終止 TLS,且正確的要求配置不知道有 Kestrel。TLS is terminated by the reverse proxy, and Kestrel isn't made aware of the correct request scheme. OAuth 和 OIDC 在此組態中也失敗,因為它們會產生不正確的重新導向。OAuth and OIDC also fail in this configuration because they generate incorrect redirects. UseIISIntegration 在 IIS 後端執行時,會新增並設定轉送標頭中介軟體,但沒有相符的 Linux (Apache 或 Nginx 整合) 自動組態。UseIISIntegration adds and configures Forwarded Headers Middleware when running behind IIS, but there's no matching automatic configuration for Linux (Apache or Nginx integration).

若要從非 IIS 案例的 Proxy 轉送配置,請新增並設定轉送標頭中介軟體。To forward the scheme from the proxy in non-IIS scenarios, add and configure Forwarded Headers Middleware. Startup.ConfigureServices 中,使用下列程式碼:In Startup.ConfigureServices, use the following 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();
    });
}

在 Azure 中提供新的容器映像前,您都必須針對設為 trueASPNETCORE_FORWARDEDHEADERS_ENABLED 建立應用程式設定 (環境變數)。Until new container images are provided in Azure, you must create an app setting (environment variable) for ASPNETCORE_FORWARDEDHEADERS_ENABLED set to true. 如需詳細資訊,請參閱 Templates do not work in Antares Linux due to missing scheme forwarders (aspnet/AspNetCore #4135) (因為遺漏配置轉寄站,所以範本在 Antares Linux 中不作用 (aspnet/AspNetCore #4135))。For more information, see Templates do not work in Antares Linux due to missing scheme forwarders (aspnet/AspNetCore #4135).

疑難排解Troubleshoot

當標頭未如預期般傳送時,請啟用記錄功能When headers aren't forwarded as expected, enable logging. 如果記錄提供的資訊不足,無法針對問題進行疑難排解,則請列舉伺服器所收到的要求標頭。If the logs don't provide sufficient information to troubleshoot the problem, enumerate the request headers received by the server. 使用內嵌中介軟體將要求標頭寫入應用程式回應或記錄標頭。Use inline middleware to write request headers to an app response or log the headers.

若要將標頭寫入至應用程式的回應,將下列終端機內嵌中介軟體緊接著放置於 Startup.Configure 中對 UseForwardedHeaders 的呼叫之後:To write the headers to the app's response, place the following terminal inline middleware immediately after the call to 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}");
});

您可以寫入至記錄,而不是回應本文。You can write to logs instead of the response body. 寫入至記錄可讓網站在偵錯時正常運作。Writing to logs allows the site to function normally while debugging.

若要寫入記錄而不是回應本文:To write logs rather than to the response body:

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: {REMOTE_IP_ADDRESS}", 
        context.Connection.RemoteIpAddress);

    await next();
});

處理後,X-Forwarded-{For|Proto|Host} 值會移至 X-Original-{For|Proto|Host}When processed, X-Forwarded-{For|Proto|Host} values are moved to X-Original-{For|Proto|Host}. 如果指定的標頭中有多個值,請注意,「轉送的標頭中介軟體」會以相反順序 (從右至左) 處理標頭。If there are multiple values in a given header, note Forwarded Headers Middleware processes headers in reverse order from right to left. 預設的 ForwardLimit 是 1 (一),因此除非 ForwardLimit 的值增加,否則只會處理標頭中最右邊的值。The default ForwardLimit is 1 (one), so only the rightmost value from the headers is processed unless the value of ForwardLimit is increased.

要求的原始遠端 IP 必須符合 KnownProxiesKnownNetworks 清單中的項目,系統才會處理轉送的標頭。The request's original remote IP must match an entry in the KnownProxies or KnownNetworks lists before forwarded headers are processed. 這可藉由不接受來自不受信任 Proxy 的轉送子,以限制標頭詐騙行為。This limits header spoofing by not accepting forwarders from untrusted proxies. 當偵測到未知的 Proxy 時,記錄會指出 Proxy 的位址:When an unknown proxy is detected, logging indicates the address of the proxy:

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

在上述範例中,10.0.0.100 是 Proxy 伺服器。In the preceding example, 10.0.0.100 is a proxy server. 如果伺服器是信任的 Proxy,請將伺服器的 IP 位址新增至 Startup.ConfigureServices 中的 KnownProxies (或將信任的網路新增至 KnownNetworks)。If the server is a trusted proxy, add the server's IP address to KnownProxies (or add a trusted network to KnownNetworks) in Startup.ConfigureServices. 如需詳細資訊,請參閱轉送的標頭中介軟體選項一節。For more information, see the Forwarded Headers Middleware options section.

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

重要

只允許信任的 Proxy 以及網路轉送標頭。Only allow trusted proxies and networks to forward headers. 否則,IP 詐騙攻擊有可能發生。Otherwise, IP spoofing attacks are possible.

憑證轉送Certificate forwarding

在 Azure 上On Azure

請參閱 Azure 文件以設定 Azure Web Apps。See the Azure documentation to configure Azure Web Apps. 在您應用程式的 Startup.Configure 方法中,於 app.UseAuthentication(); 呼叫的前面新增下列程式碼:In your app's Startup.Configure method, add the following code before the call to app.UseAuthentication();:

app.UseCertificateForwarding();

您也需要設定憑證轉送中介軟體以指定 Azure 使用的標頭名稱。You'll also need to configure the Certificate Forwarding middleware to specify the header name that Azure uses. 在您應用程式的 Startup.ConfigureServices 方法中,新增下列程式碼以設定標頭,中介軟體會在其中建置憑證:In your app's Startup.ConfigureServices method, add the following code to configure the header from which the middleware builds a certificate:

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

搭配其他 Web ProxyWith other web proxies

如果您使用的 Proxy 不是 IIS 或 Azure Web Apps 應用程式要求路由,請設定您的 Proxy 轉送它在 HTTP 標頭中收到的憑證。If you're using a proxy that isn't IIS or Azure's Web Apps Application Request Routing, configure your proxy to forward the certificate it received in an HTTP header. 在您應用程式的 Startup.Configure 方法中,於 app.UseAuthentication(); 呼叫的前面新增下列程式碼:In your app's Startup.Configure method, add the following code before the call to app.UseAuthentication();:

app.UseCertificateForwarding();

您也需要設定憑證轉送中介軟體以指定標頭名稱。You'll also need to configure the Certificate Forwarding middleware to specify the header name. 在您應用程式的 Startup.ConfigureServices 方法中,新增下列程式碼以設定標頭,中介軟體會在其中建置憑證:In your app's Startup.ConfigureServices method, add the following code to configure the header from which the middleware builds a certificate:

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

最後,如果 Proxy 不是使用 base64 編碼憑證 (和 Nginx 一樣),則請設定 HeaderConverter 選項。Finally, if the proxy is doing something other than base64 encoding the certificate (as is the case with Nginx), set the HeaderConverter option. 請考慮 Startup.ConfigureServices 中的下列範例:Consider the following example 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;
    }
});

其他資源Additional resources