【问题标题】:`X-Forwarded-For` is not used by ASP.Net Core behind reverse proxy反向代理后面的 ASP.Net Core 不使用“X-Forwarded-For”
【发布时间】:2021-11-04 05:29:48
【问题描述】:

我试图在我的 ASP.Net Core 2.1 MVC 中获取请求的远程 IP 地址(即发送请求的客户端的 IP)控制器(在 .Net Docker 容器中运行)。考虑到我的 ASP.Net Core 应用程序位于 NGINX 反向代理之后(在 NGINX Docker 容器中运行)。

众所周知,当反向代理将请求重定向到我的 .Net Core 应用程序时,它会更改我的请求的源 IP(TCP/IP 层),因此,我配置 NGINX 以添加 X-Forwarded-For 与原始 IP到请求。从 NGINX 容器重定向到 .Net 容器的请求在标头中有X-Forwarded-For

当然,我配置了 .Net Core 以了解这一点:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
    // Rewrite the header when being redirected (this is required because we are behind reverse proxy)
    var forwardedHeadersOptions = new ForwardedHeadersOptions
    {
        ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
        KnownProxies = { IPAddress.Parse("172.20.10.2"), IPAddress.Parse("172.20.10.3"), IPAddress.Parse("172.20.10.4") },
    };

    forwardedHeadersOptions.KnownNetworks.Add(
        new IPNetwork(IPAddress.Parse("172.0.0.0"), 8));
    forwardedHeadersOptions.KnownNetworks.Add(
        new IPNetwork(IPAddress.Parse("127.0.0.1"), 8));

    app.UseForwardedHeaders(forwardedHeadersOptions);
    ...

但是,HTTPContext.Connection.RemoteIPAddress 仍然返回 172.20.10.3(NGINX 容器 IP,不是真正的远程 IP):

logger.LogDebug("Remote IP Address: " + Request.HttpContext.Connection.RemoteIpAddress.ToString());

远程IP地址:172.20.10.3

我在 .Net Core 中检查了我的标头,它有 X-Forwarded-For 和正确的原始远程 IP 地址:

logger.LogDebug("X-Forwarded-For Header Feature: " + HttpContext.Request.Headers["X-Forwarded-For"]);

X-Forwarded-For 标头功能:85.XX.4.121

有人知道我缺少什么吗?为什么 RemoteIPAddress 仍然返回 NGINX docker 容器的 IP 而不是真实的远程 IP 地址?

更新

我的Program.cs

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseUrls("http://*:5000")
            .UseStartup<Startup>()
            .Build();
}

我还尝试通过像这样配置其服务来配置ForwarededHeadersOptions

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    //options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.0.0.0"), 8));
    options.RequireHeaderSymmetry = false;
    options.ForwardLimit = null;
    options.KnownProxies.Add(IPAddress.Parse("172.20.10.3"));
    //options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("127.0.0.1"), 8));
});

没有成功...

更新 2

好吧,我想我是在正确的方式,RemoteIPAddress 返回的 IP 地址是 ::ffff:172.20.10.20,而不是 172.20.10.20!我不知道它们是不同的。 official documentation 帮助我发现了这一点。

【问题讨论】:

  • 当它到达您的应用程序时,您是否有多个 X-Forwarded-For 标头? iirc 默认情况下,默认找到时将使用 first X-Forwarded-For。另外请确保,您可以将ForwardLimit 设置为null 以取消限制,但前提是设置了KnowProxiesKnownNetworks(如您的情况):docs.microsoft.com/en-us/dotnet/api/…。默认情况下,ForwardLimit 设置为 1,因此它只会处理 FIRST 条目,如果您有多个代理,这可能会成为问题...
  • ...每个代理设置自己的标头
  • @Tseng,我已经尝试将ForwardLimit 设置为null,但不幸的是没有成功,我只有一个反向代理,我的标题中只有一个X-Forwarded-For(如图所示)。我不知道那可能是什么......完全奇怪......
  • 还要注意,Programm.cs 中的UseIISIntegration 调用,在默认平台中 注册了UseForwardedHeaders(或曾经使用过的)中间件。尝试不要在 ConfigureServices 中使用 UseForwardedHeaderservices.Configure&lt;ForwardedHeadersOptions&gt;(options =&gt; ...),这样您就不会意外拥有两个中间件,并且可以确保您的配置用于正确的中间件,因为它是通过 DI 解决的,请参阅 github.com/aspnet/IISIntegration/blob/2.1.2/src/…
  • @Tseng,我也试过了,但没有成功...我对问题添加了一个小更新

标签: c# asp.net-core .net-core


【解决方案1】:

我从RemoteIPAddress 获得的 IP 是表示为 IPv6 的 IPv4(是 ::ffff:172.20.10.20,而不是 172.20.10.20!)。我只使用了 IP 的 IPv4 部分,因此在我的情况下 KnownProxies 是错误的。我也应该使用 v6 表示部分输入完整的 IPv4 地址。

官方文档显示:

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1

根据评论要求更新:

所以在我的例子中,代码应该是这样的:

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.RequireHeaderSymmetry = false;
    options.ForwardLimit = null;
    options.KnownProxies.Add(IPAddress.Parse("::ffff:172.20.10.20")); // <<-- Notice the full format of the IP address.
});

【讨论】:

  • 你能告诉我们你做了什么options.KnownProxies.Add(IPAddress.Parse("::ffff:172.20.10.20"));
  • @user960567 抱歉我没听懂你的问题?
  • 我应该用什么代码来解决这个问题?
  • @user960567 我更新了答案,向您展示了增强的代码。
  • 谢谢。就我而言,我还需要更新 ForwardLimit。
【解决方案2】:

根据官方文档,如果您使用的是Apache或Nginx集成,应在Startup.ConfigureServices方法中添加以下代码。

// using Microsoft.AspNetCore.HttpOverrides;

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

然后最重要的是,在Configure 方法中使用

app.UseForwardedHeaders();

进一步假设在 nginx conf 文件中的某个位置,使用

proxy_set_header   Host $host;
proxy_set_header   X-Real-IP $remote_addr;
proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header   X-Forwarded-Host $server_name;

现在X-Forwarded-For 中的第一个条目将是真正的客户端 IP。

重要提示:如果您想保护应用程序并且不允许攻击者注入 X-Forwarded-For,请阅读此answer

请参阅Forward the scheme for Linux and non-IIS reverse proxiesConfigure NginxDealing with invalid headers

【讨论】:

    猜你喜欢
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 2015-11-18
    • 2015-06-16
    • 2017-02-18
    • 2017-12-31
    • 2020-03-26
    相关资源
    最近更新 更多