.Net核心X-Forwarded-Proto标头未正确传递给Nginx

时间:2019-09-26 20:54:45

标签: nginx asp.net-core .net-core http-headers

很抱歉,编辑历史记录,但是这个问题对我来说真的很不清楚,很难找到确切的问题。

我有一个 .Net-Core Web应用程序,该应用程序在 Nginx 之后运行,并且 X-Forwarded-Proto 始终通过{{1 }},而不是http

Startup.cs

https

Nginx conf

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

            services.AddMvc();

        }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //first middlewear
            app.UseForwardedHeaders();
             //and the rest
         }

Nginx.conf

server {
    listen        80;
    server_name   example.com;
    location / {
        proxy_pass         http://localhost:5001/;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

access.log记录

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    #cloudflare real ip
    #https://support.cloudflare.com/hc/en-us/articles/200170786-Restoring-original-visitor-IPs-Logging-visitor-IP-addresses-with-mod-cloudflare-#12345681
    set_real_ip_from 173.245.48.0/20;
    real_ip_header    X-Forwarded-For;
    real_ip_recursive on;

    log_format  main  '"$scheme" $remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

您可以看到我登录的 $ scheme 总是 HTTP

解决此问题的一种方法是将Scheme强制为 HTTPS ,如下所示:

"http" 185.108.83.156 - - [03/Oct/2019:19:59:33 +0300] "GET /auth/signin/Facebook?returnUrl=%2F HTTP/1.1" 302 0 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" "156"

来自https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.2#forwarded-headers-middleware-options

但是使用这种解决方案,我不会传递标头,并且会丢失一些信息。

那么有人对此案有解决方案吗?

5 个答案:

答案 0 :(得分:1)

您的Startup.cs文件很好,但是您没有为Kesterl配置ssl。

您需要为.net核心应用程序配置X.509 ssl证书

来自https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-2.2#when-to-use-kestrel-with-a-reverse-proxy-1

  

仅反向代理服务器需要X.509证书,并且该证书   服务器可以与内部网络上的应用服务器通信   使用纯HTTP

因此,您需要执行7个主要步骤:
1)从CloudFlare ORIGIN CA获取SSL证书
2)在您的服务器中安装ssl证书
3)创建一个PFX文件,以便您的Kesterl Server可以读取它。
4)配置Kesterl https端点。
5)修改您的Nginx服务器以监听端口443,然后重定向到Kestrel监听端口
6)根据您的配置修改服务文件
7)将Cloudflare更改为运行严格模式

步骤1-从cloudflare获取ssl证书:
转到Cloudflare的信息中心,然后选择SSL / TLS->原始服务器->创建证书。 按照说明进行操作,然后在过程结束时将有2个文件: example.com.key example.com.pem

第2步-将文件放在服务器中etc/ssl文件夹中

第3步-创建PFX文件,以便Kesterl可以使用证书:
在您的服务器上运行它:

openssl pkcs12 -export -out example.pfx -inkey example.com.key -in example.com.pem

这将生成 example.pfx ,并将其放置在同一文件夹中。

第4步-配置Kesterl https端点。
从第3步开始,您应该已经在该步骤中需要使用密码。
在您的appsetting.json处放置以下行:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "Kestrel": {
    "Endpoints": {
      "HTTPS": {
        "Url": "https://localhost:5001",
        "Certificate": {
          "Path": "/etc/ssl/example.pfx",
          "Password": "**********"
        }
      }
    }
  }

第5步-配置Nginx监听端口443,如下所示:

server {
    #listen        80;
    listen                 *:443 ssl;
    ssl_certificate        /etc/ssl/example.pem;
    ssl_certificate_key    /etc/ssl/example.key;
    server_name            example.com
    location / {
        proxy_pass         https://localhost:5001/;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

第6步-像这样配置服务文件:

  [Unit]
    Description=example

    [Service]
    WorkingDirectory=/var/www/example
    ExecStart=/usr/bin/dotnet /var/www/example/exampleSite.dll
    Restart=always
    # Restart service after 10 seconds if the dotnet service crashes:
    RestartSec=10
    KillSignal=SIGINT
    SyslogIdentifier=example
    User=www-data
    Environment=ASPNETCORE_ENVIRONMENT=Staging
    Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
    Environment=ASPNETCORE_HTTPS_PORT=5001
    Environment=ASPNETCORE_URLS=https://localhost:5001

    [Install]
    WantedBy=multi-user.target

步骤7-将SSL / TLS上的Cloudflare更改为使用严格模式

重新启动您的应用程序+ Nginx,您的服务器现在应该像这样工作:

  

请求-> Cloudflare(HTTPS)-> Nginx(HTTPS)-> Example.com

答案 1 :(得分:0)

通常,HTTP标头不接受非ASCII字符。生成的Urls必须正确编码,Redirect方法无法为您完成。

快速修复可能是使用WebUtility.UrlEncode

using System.Net;
// ...
var encodedLocationName = WebUtility.UrlEncode(locationName);
return Redirect("~/locations/" + encodedLocationName);

答案 2 :(得分:0)

这似乎与NGinx文件和Cloudflare的设置方式有关。在配置中,您设置为

  

HTTPS-> Cloudflare-> HTTP->您的服务器

这就是为什么Scheme在您的nginx日志中始终为“ http”的原因。当Cloudflare通过HTTP将请求传递到您的服务器时。您应该在Cloudflare和您之间设置TLS,这将在nginx配置上启用端口443,这会将方案设置为HTTPS。强迫dotnet相信它是通过HTTPS处理的,这是无效的,因为Cloudflare正在通过公共Internet发送未加密的客户数据。

https://support.cloudflare.com/hc/en-us/articles/115000479507-Managing-Cloudflare-Origin-CA-certificates

Cloudflare的文档列出了如何使用NGinx进行设置。

答案 3 :(得分:0)

您仅在端口80上运行nginx而没有ssl,因此$scheme变量将始终为http。参见http://nginx.org/r/$scheme

如果您关心https,那么通过HTTPS保护Cloudflare和您的后端之间的连接也是一个好主意;这样,您的$scheme变量将被正确填充。否则,您也可以用硬编码https代替$scheme,但是这样就无法达到进行条件测试和在真正的最终Net后端进行重定向的目的。

答案 4 :(得分:-1)

请在您的nginx文件中设置适当的字符集。

这里是文档 http://nginx.org/en/docs/http/ngx_http_charset_module.html#charset_types