配置 ASP.NET Core 以使用代理服务器和负载均衡器Configure ASP.NET Core to work with proxy servers and load balancers

在 ASP.NET Core 推荐配置中,应用使用 IIS/ASP.NET Core 模块、Nginx 或 Apache 进行托管。代理服务器、负载均衡器和其他网络设备通常会在请求到达应用之前隐藏有关请求的信息:

  • 当通过 HTTP 代理 HTTPS 请求时,原方案 (HTTPS) 将丢失,并且必须在标头中转接。
  • 由于应用收到来自代理的请求,而不是 Internet 或公司网络上请求的真实源,因此原始客户端 IP 地址也必须在标头中转接。

此信息在请求处理中可能很重要,例如在重定向、身份验证、链接生成、策略评估和客户端地理位置中。

按照约定,代理转接 HTTP 标头中的信息。

来自 包的转接头中间件读取这些标头,并填充 HttpContext 上的关联字段。

中间件更新:

  • – 使用 标头值进行设置。影响中间件如何设置 RemoteIpAddress 的其他设置。有关详细信息,请参阅转接头中间件选项
  • – 使用 X-Forwarded-Proto 标头值进行设置。
  • HttpContext.Request.Host – 使用 X-Forwarded-Host 标头值进行设置。

可以配置转接头中间件。默认设置为:

  • 应用和请求源之间只有一个代理 。
  • 仅将环回地址配置为已知代理和已知网络。
  • 转接头被命名为 X-Forwarded-ForX-Forwarded-Proto

并非所有网络设备均可在没有其他配置的情况下添加 X-Forwarded-ForX-Forwarded-Proto 标头。如果代理请求在到达应用时未包含这些标头,请查阅设备制造商提供的指导。如果设备使用 X-Forwarded-ForX-Forwarded-Proto 以外的其他标头名称,请设置 ForwardedForHeaderName 和 选项,使其与设备所用的标头名称相匹配。有关详细信息,请参阅转接头中间件选项和。

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

当应用托管在 IIS 和 ASP.NET Core 模块后方的时,转接头中间件由 IIS 集成中间件默认启用。由于转接头的信任问题(例如,),转接头中间件被激活为首先在中间件管道中运行,并具有特定于 ASP.NET Core 模块的受限配置。中间件配置为转接 X-Forwarded-ForX-Forwarded-Proto 标头,并且被限制到单个本地 localhost 代理。如果需要其他配置,请参阅转接头中间件选项

其他代理服务器和负载均衡器方案Other proxy server and load balancer scenarios

除在进程外托管时使用 之外,不会默认启用转接头中间件。必须启用应用的转接头中间件才能处理带有 UseForwardedHeaders 的转接头。启用中间件后,如果没有为中间件指定 ,那么默认的 ForwardedHeadersOptions.ForwardedHeaders 是 。

为中间件配置 ForwardedHeadersOptions 以转接 Startup.ConfigureServices 中的 X-Forwarded-ForX-Forwarded-Proto 标头。调用其他中间件之前,先调用 Startup.Configure 中的 方法:

备注

如果没有在 Startup.ConfigureServices 中指定任何 ForwardedHeadersOptions,或未使用 直接指定到扩展方法,则要转接的默认标头为 ForwardedHeaders.None必须为 属性配置要转接的标头。

Nginx 配置Nginx configuration

要转发 X-Forwarded-ForX-Forwarded-Proto 标头,请参阅 。有关详细信息,请参阅 NGINX:使用转发标头

Apache 配置Apache configuration

X-Forwarded-For 将会自动添加(请参阅 Apache 模块 mod_proxy:反向代理请求标头)。要了解如何转发 X-Forwarded-Proto 标头,请参阅 。

转接头中间件选项Forwarded Headers Middleware options

控制转接头中间件的行为。以下示例更改了默认值:

  • 将转接头中的条目数量限制为 2
  • 添加已知的代理地址 127.0.10.1
  • 将转接头名称从默认的 X-Forwarded-For 更改为 X-Forwarded-For-My-Custom-Header-Name
  1. services.Configure<ForwardedHeadersOptions>(options =>
  2. {
  3. options.ForwardLimit = 2;
  4. options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
  5. options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
  6. });

方案与使用案例Scenarios and use cases

无法添加转接头并且所有请求都安全的情况When it isn't possible to add forwarded headers and all requests are secure

在某些情况下,可能无法将转接头添加到代理到应用的请求中。如果代理强制将所有公共外部请求执行为 HTTPS,则在使用任何类型的中间件之前,可以在 Startup.Configure 中手动设置该方案:

  1. app.Use((context, next) =>
  2. {
  3. context.Request.Scheme = "https";
  4. return next();
  5. });

此代码可以通过环境变量或者开发环境或过渡环境中的其他配置设置来禁用。

处理改变请求路径的基路径和代理Deal with path base and proxies that change the request path

一些代理可完整地传递路径,但是会删除应用基路径以便路由可正常工作。 中间件将路径拆分为 HttpRequest.Path,将应用基路径拆分为 。

如果 /foo 是作为 /foo/api/1 传递的代理路径的应用基路径,则中间件使用以下命令将 Request.PathBase 设置为 /foo,将 Request.Path 设置为 /api/1

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

当再次反向调用中间件时,将重新应用原始路径和基路径。要详细了解中间件处理顺序,请参阅 ASP.NET Core 中间件

如果代理剪裁路径(例如,将 /foo/api/1 转接到 /api/1),请通过设置请求的 属性来修复重定向和链接:

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

如果代理要添加路径数据,请使用 StartsWithSegments 并分配给 属性,从而放弃部分路径以修复重定向和链接:

  1. app.Use((context, next) =>
  2. {
  3. if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
  4. {
  5. context.Request.Path = remainder;
  6. }
  7. return next();
  8. });

如果代理不使用名为 X-Forwarded-ForX-Forwarded-Proto 的标头来转发代理地址/端口和原始架构信息,则设置 ForwardedForHeaderName 和 选项,使其与代理所用的标头名称相匹配:

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

对表示为 IPv6 地址的 IPv4 地址进行配置Configuration for an IPv4 address represented as an IPv6 address

如果服务器使用双模式套接字,则采用 IPv6 格式提供 IPv4 地址(例如,IPv4 格式的 10.0.0.1 以 IPv6 格式表示为 ::ffff:10.0.0.1::ffff:a00:1)。请参阅 。通过查看 HttpContext.Connection.RemoteIpAddress 来确定是否需要采用此格式。

在以下示例中,提供转接头的网络地址以 IPv6 格式添加到 KnownNetworks 列表中。

IPv4 地址:10.11.12.1/8

转换后的 IPv6 地址:::ffff:10.11.12.1转换后的前缀长度:104

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

如果将站点部署到 Azure Linux 应用服务、Azure Linux 虚拟机 (VM),或者部署到除 IIS 之外的任何其他反向代理之后,调用 和 UseHsts 的应用都会使站点进入无限循环。反向代理终止 TLS,并且 Kestrel 未发现正确的请求方案。由于 OAuth 和 OIDC 生成了错误的重定向,因此它们在此配置中也会出现故障。 在 IIS 之后运行时会添加和配置转接头中间件,但 Linux(Apache 或 Nginx 集成)没有匹配的自动配置。

要从非 IIS 方案中的代理中转发方案,请添加并配置转接头中间件。Startup.ConfigureServices 中,使用以下代码:

  1. // using Microsoft.AspNetCore.HttpOverrides;
  2. if (string.Equals(
  3. Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
  4. "true", StringComparison.OrdinalIgnoreCase))
  5. {
  6. services.Configure<ForwardedHeadersOptions>(options =>
  7. {
  8. options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
  9. ForwardedHeaders.XForwardedProto;
  10. // Only loopback proxies are allowed by default.
  11. // Clear that restriction because forwarders are enabled by explicit
  12. // configuration.
  13. options.KnownNetworks.Clear();
  14. options.KnownProxies.Clear();
  15. });
  16. }

转发证书Certificate forwarding

AzureAzure

若要为证书转发配置 Azure 应用服务,请参阅为 Azure 应用服务配置 TLS 相互身份验证以下指南与配置 ASP.NET Core 应用相关。

Startup.Configure 中,在调用 app.UseAuthentication(); 前添加以下代码:

  1. app.UseCertificateForwarding();

配置证书转发中间件,以指定 Azure 使用的标头名称。Startup.ConfigureServices 中,添加以下代码来配置中间件从中生成证书的标头:

如果使用的代理不是 IIS 或 Azure 应用服务的应用程序请求路由 (ARR),请配置代理,以便转发其在 HTTP 标头中收到的证书。Startup.Configure 中,在调用 app.UseAuthentication(); 前添加以下代码:

  1. app.UseCertificateForwarding();

配置证书转发中间件,以指定标头名称。Startup.ConfigureServices 中,添加以下代码来配置中间件从中生成证书的标头:

  1. services.AddCertificateForwarding(options =>

如果代理不在对证书进行 base64 编码(与 Nginx 的情况一样),请设置 选项。请看下面 Startup.ConfigureServices 中的示例:

  1. services.AddCertificateForwarding(options =>
  2. {
  3. options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
  4. options.HeaderConverter = (headerValue) =>
  5. {
  6. var clientCertificate =
  7. /* some conversion logic to create an X509Certificate2 */
  8. return clientCertificate;
  9. }
  10. });

疑难解答Troubleshoot

如果未按预期转接标头,请启用日志记录如果日志没有提供足够的信息来解决问题,请枚举服务器收到的请求标头。使用内联中间件将请求标头写入应用程序响应或记录标头。

要将标头写入应用的响应,请在 Startup.Configure 中调用 后立即放置以下终端内联中间件:

  1. app.Run(async (context) =>
  2. {
  3. context.Response.ContentType = "text/plain";
  4. // Request method, scheme, and path
  5. await context.Response.WriteAsync(
  6. $"Request Method: {context.Request.Method}{Environment.NewLine}");
  7. await context.Response.WriteAsync(
  8. $"Request Scheme: {context.Request.Scheme}{Environment.NewLine}");
  9. await context.Response.WriteAsync(
  10. $"Request Path: {context.Request.Path}{Environment.NewLine}");
  11. // Headers
  12. await context.Response.WriteAsync($"Request Headers:{Environment.NewLine}");
  13. foreach (var header in context.Request.Headers)
  14. {
  15. await context.Response.WriteAsync($"{header.Key}: " +
  16. $"{header.Value}{Environment.NewLine}");
  17. }
  18. await context.Response.WriteAsync(Environment.NewLine);
  19. // Connection: RemoteIp
  20. await context.Response.WriteAsync(
  21. $"Request RemoteIp: {context.Connection.RemoteIpAddress}");
  22. });

可以写入日志,而不是响应正文。借助写入日志,站点可在调试时正常运行。

要写入日志而不是响应正文,请执行以下操作:

  • ILogger<Startup> 注入到 Startup 类中,如在启动时创建日志中所述。
  • Startup.Configure 中调用 之后,立即放置以下内联中间件。
  1. app.Use(async (context, next) =>
  2. {
  3. // Request method, scheme, and path
  4. _logger.LogDebug("Request Method: {Method}", context.Request.Method);
  5. _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
  6. _logger.LogDebug("Request Path: {Path}", context.Request.Path);
  7. // Headers
  8. foreach (var header in context.Request.Headers)
  9. {
  10. _logger.LogDebug("Header: {Key}: {Value}", header.Key, header.Value);
  11. }
  12. // Connection: RemoteIp
  13. _logger.LogDebug("Request RemoteIp: {RemoteIpAddress}",
  14. context.Connection.RemoteIpAddress);
  15. await next();
  16. });

处理时,X-Forwarded-{For|Proto|Host} 值将移至 X-Original-{For|Proto|Host}如果给定标头中有多个值,则转接头中间件按照从右向左的相反顺序处理标头。默认 ForwardLimit1(一),因此只会处理标头最右侧的值,除非增加 ForwardLimit 的值。

在处理转接头之前,请求的原始远程 IP 必须与 KnownProxiesKnownNetworks 列表中的条目匹配。这通过不接受来自不受信任的代理的转发器来限制标头欺骗。检测到未知代理时,日志记录会指出代理的地址:

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

在上述示例中,10.0.0.100 是代理服务器。如果该服务器是受信任的代理,请将服务器的 IP 地址添加到 Startup.ConfigureServices 中的 KnownProxies(或将受信任的网络添加到 KnownNetworks)。有关详细信息,请参阅转接头中间件选项部分。

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

重要

仅允许受信任的代理和网络转接头。否则,可能会受到 攻击。

其他资源Additional resources

在 ASP.NET Core 推荐配置中,应用使用 IIS/ASP.NET Core 模块、Nginx 或 Apache 进行托管。代理服务器、负载均衡器和其他网络设备通常会在请求到达应用之前隐藏有关请求的信息:

  • 当通过 HTTP 代理 HTTPS 请求时,原方案 (HTTPS) 将丢失,并且必须在标头中转接。
  • 由于应用收到来自代理的请求,而不是 Internet 或公司网络上请求的真实源,因此原始客户端 IP 地址也必须在标头中转接。

此信息在请求处理中可能很重要,例如在重定向、身份验证、链接生成、策略评估和客户端地理位置中。

转接头Forwarded headers

按照约定,代理转接 HTTP 标头中的信息。

来自 Microsoft.AspNetCore.HttpOverrides 包的转接头中间件读取这些标头,并填充 上的关联字段。

中间件更新:

可以配置转接头中间件默认设置默认设置为:

  • 应用和请求源之间只有一个代理 。
  • 仅将环回地址配置为已知代理和已知网络。
  • 转接头被命名为 X-Forwarded-ForX-Forwarded-Proto

并非所有网络设备均可在没有其他配置的情况下添加 X-Forwarded-ForX-Forwarded-Proto 标头。如果代理请求在到达应用时未包含这些标头,请查阅设备制造商提供的指导。如果设备使用 X-Forwarded-ForX-Forwarded-Proto 以外的其他标头名称,请设置 和 ForwardedProtoHeaderName 选项,使其与设备所用的标头名称相匹配。有关详细信息,请参阅和配置使用不同标头名称的代理

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

当应用托管在 IIS 和 ASP.NET Core 模块后方的进程外时,转接头中间件由 默认启用。由于转接头的信任问题(例如,IP 欺骗),转接头中间件被激活为首先在中间件管道中运行,并具有特定于 ASP.NET Core 模块的受限配置。中间件配置为转接 X-Forwarded-ForX-Forwarded-Proto 标头,并且被限制到单个本地 localhost 代理。如果需要其他配置,请参阅。

其他代理服务器和负载均衡器方案Other proxy server and load balancer scenarios

除在托管时使用 IIS 集成之外,不会默认启用转接头中间件。必须启用应用的转接头中间件才能处理带有 的转接头。启用中间件后,如果没有为中间件指定 ForwardedHeadersOptions,那么默认的 是 ForwardedHeaders.None

为中间件配置 以转接 Startup.ConfigureServices 中的 X-Forwarded-ForX-Forwarded-Proto 标头。调用其他中间件之前,先调用 Startup.Configure 中的 UseForwardedHeaders 方法:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc();
  4. services.Configure<ForwardedHeadersOptions>(options =>
  5. {
  6. options.ForwardedHeaders =
  7. ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
  8. });
  9. }
  10. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  11. {
  12. app.UseForwardedHeaders();
  13. if (env.IsDevelopment())
  14. {
  15. app.UseDeveloperExceptionPage();
  16. }
  17. else
  18. {
  19. app.UseExceptionHandler("/Home/Error");
  20. }
  21. app.UseStaticFiles();
  22. // In ASP.NET Core 1.x, replace the following line with: app.UseIdentity();
  23. app.UseAuthentication();
  24. app.UseMvc();
  25. }

如果没有在 Startup.ConfigureServices 中指定任何 ,或未使用 UseForwardedHeaders 直接指定到扩展方法,则要转接的默认标头为 。必须为 ForwardedHeaders 属性配置要转接的标头。

要转发 X-Forwarded-ForX-Forwarded-Proto 标头,请参阅 。有关详细信息,请参阅 NGINX:使用转发标头

Apache 配置Apache configuration

X-Forwarded-For 将会自动添加(请参阅 Apache 模块 mod_proxy:反向代理请求标头)。要了解如何转发 X-Forwarded-Proto 标头,请参阅 。

转接头中间件选项Forwarded Headers Middleware options

控制转接头中间件的行为。以下示例更改了默认值:

  • 将转接头中的条目数量限制为 2
  • 添加已知的代理地址 127.0.10.1
  1. services.Configure<ForwardedHeadersOptions>(options =>
  2. {
  3. options.ForwardLimit = 2;
  4. options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
  5. options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
  6. });

方案与使用案例Scenarios and use cases

无法添加转接头并且所有请求都安全的情况When it isn't possible to add forwarded headers and all requests are secure

在某些情况下,可能无法将转接头添加到代理到应用的请求中。如果代理强制将所有公共外部请求执行为 HTTPS,则在使用任何类型的中间件之前,可以在 Startup.Configure 中手动设置该方案:

此代码可以通过环境变量或者开发环境或过渡环境中的其他配置设置来禁用。

处理改变请求路径的基路径和代理Deal with path base and proxies that change the request path

一些代理可完整地传递路径,但是会删除应用基路径以便路由可正常工作。 中间件将路径拆分为 HttpRequest.Path,将应用基路径拆分为 。

如果 /foo 是作为 /foo/api/1 传递的代理路径的应用基路径,则中间件使用以下命令将 Request.PathBase 设置为 /foo,将 Request.Path 设置为 /api/1

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

当再次反向调用中间件时,将重新应用原始路径和基路径。要详细了解中间件处理顺序,请参阅 ASP.NET Core 中间件

如果代理剪裁路径(例如,将 /foo/api/1 转接到 /api/1),请通过设置请求的 属性来修复重定向和链接:

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

如果代理要添加路径数据,请使用 StartsWithSegments 并分配给 属性,从而放弃部分路径以修复重定向和链接:

  1. app.Use((context, next) =>
  2. {
  3. if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
  4. {
  5. context.Request.Path = remainder;
  6. }
  7. return next();
  8. });

如果代理不使用名为 X-Forwarded-ForX-Forwarded-Proto 的标头来转发代理地址/端口和原始架构信息,则设置 ForwardedForHeaderName 和 选项,使其与代理所用的标头名称相匹配:

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

对表示为 IPv6 地址的 IPv4 地址进行配置Configuration for an IPv4 address represented as an IPv6 address

如果服务器使用双模式套接字,则采用 IPv6 格式提供 IPv4 地址(例如,IPv4 格式的 10.0.0.1 以 IPv6 格式表示为 ::ffff:10.0.0.1::ffff:a00:1)。请参阅 。通过查看 HttpContext.Connection.RemoteIpAddress 来确定是否需要采用此格式。

在以下示例中,提供转接头的网络地址以 IPv6 格式添加到 KnownNetworks 列表中。

IPv4 地址:10.11.12.1/8

转换后的 IPv6 地址:::ffff:10.11.12.1转换后的前缀长度:104

也可以提供十六进制格式的地址(10.11.12.1 以 IPv6 格式表示为 ::ffff:0a0b:0c01)。将 IPv4 地址转换为 IPv6 时,将 96 添加到 CIDR 前缀长度(示例中的 8)以说明其他 ::ffff: IPv6 前缀 (8 + 96 = 104)。

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

转发 Linux 和非 IIS 反向代理的方案Forward the scheme for Linux and non-IIS reverse proxies

如果将站点部署到 Azure Linux 应用服务、Azure Linux 虚拟机 (VM),或者部署到除 IIS 之外的任何其他反向代理之后,调用 UseHttpsRedirection 和 的应用都会使站点进入无限循环。反向代理终止 TLS,并且 Kestrel 未发现正确的请求方案。由于 OAuth 和 OIDC 生成了错误的重定向,因此它们在此配置中也会出现故障。UseIISIntegration 在 IIS 之后运行时会添加和配置转接头中间件,但 Linux(Apache 或 Nginx 集成)没有匹配的自动配置。

要从非 IIS 方案中的代理中转发方案,请添加并配置转接头中间件。Startup.ConfigureServices 中,使用以下代码:

  1. // using Microsoft.AspNetCore.HttpOverrides;
  2. if (string.Equals(
  3. Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
  4. "true", StringComparison.OrdinalIgnoreCase))
  5. {
  6. services.Configure<ForwardedHeadersOptions>(options =>
  7. {
  8. options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
  9. ForwardedHeaders.XForwardedProto;
  10. // Only loopback proxies are allowed by default.
  11. // Clear that restriction because forwarders are enabled by explicit
  12. // configuration.
  13. options.KnownNetworks.Clear();
  14. options.KnownProxies.Clear();
  15. });
  16. }

疑难解答Troubleshoot

如果未按预期转接标头,请启用日志记录如果日志没有提供足够的信息来解决问题,请枚举服务器收到的请求标头。使用内联中间件将请求标头写入应用程序响应或记录标头。

要将标头写入应用的响应,请在 Startup.Configure 中调用 后立即放置以下终端内联中间件:

  1. app.Run(async (context) =>
  2. {
  3. context.Response.ContentType = "text/plain";
  4. // Request method, scheme, and path
  5. await context.Response.WriteAsync(
  6. $"Request Method: {context.Request.Method}{Environment.NewLine}");
  7. await context.Response.WriteAsync(
  8. $"Request Scheme: {context.Request.Scheme}{Environment.NewLine}");
  9. await context.Response.WriteAsync(
  10. $"Request Path: {context.Request.Path}{Environment.NewLine}");
  11. // Headers
  12. await context.Response.WriteAsync($"Request Headers:{Environment.NewLine}");
  13. foreach (var header in context.Request.Headers)
  14. {
  15. await context.Response.WriteAsync($"{header.Key}: " +
  16. $"{header.Value}{Environment.NewLine}");
  17. }
  18. await context.Response.WriteAsync(Environment.NewLine);
  19. // Connection: RemoteIp
  20. await context.Response.WriteAsync(
  21. $"Request RemoteIp: {context.Connection.RemoteIpAddress}");
  22. });

可以写入日志,而不是响应正文。借助写入日志,站点可在调试时正常运行。

要写入日志而不是响应正文,请执行以下操作:

  • ILogger<Startup> 注入到 Startup 类中,如在启动时创建日志中所述。
  • Startup.Configure 中调用 之后,立即放置以下内联中间件。
  1. app.Use(async (context, next) =>
  2. {
  3. // Request method, scheme, and path
  4. _logger.LogDebug("Request Method: {Method}", context.Request.Method);
  5. _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
  6. _logger.LogDebug("Request Path: {Path}", context.Request.Path);
  7. // Headers
  8. foreach (var header in context.Request.Headers)
  9. {
  10. _logger.LogDebug("Header: {Key}: {Value}", header.Key, header.Value);
  11. }
  12. // Connection: RemoteIp
  13. _logger.LogDebug("Request RemoteIp: {RemoteIpAddress}",
  14. context.Connection.RemoteIpAddress);
  15. await next();
  16. });

处理时,X-Forwarded-{For|Proto|Host} 值将移至 X-Original-{For|Proto|Host}如果给定标头中有多个值,则转接头中间件按照从右向左的相反顺序处理标头。默认 ForwardLimit1(一),因此只会处理标头最右侧的值,除非增加 ForwardLimit 的值。

在处理转接头之前,请求的原始远程 IP 必须与 KnownProxiesKnownNetworks 列表中的条目匹配。这通过不接受来自不受信任的代理的转发器来限制标头欺骗。检测到未知代理时,日志记录会指出代理的地址:

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

在上述示例中,10.0.0.100 是代理服务器。如果该服务器是受信任的代理,请将服务器的 IP 地址添加到 Startup.ConfigureServices 中的 KnownProxies(或将受信任的网络添加到 )。有关详细信息,请参阅转接头中间件选项部分。

重要

其他资源Additional resources