繁体   English   中英

.Net core X-Forwarded-Proto header 没有正确传递给 Nginx

[英].Net core X-Forwarded-Proto header doesn't pass to Nginx properly

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

I have a .Net-Core web application that runs behind a Nginx and the X-Forwarded-Proto always passes http instead of https .

启动.cs

 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 配置

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

Nginx.conf

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;

access.log 记录

"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"

如您所见,我记录的$scheme始终是HTTP

解决该问题的解决方案是将 Scheme 强制为HTTPS ,如下所示:

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

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

但是使用此解决方案,我不会传递标题并丢失一些信息。

那么有人对这种情况有任何解决方案吗?

您的 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 服务器可以读取它。 4)配置Kesterl https端点。 5)修改您的 Nginx 服务器以侦听端口 443,然后重定向到 Kestrel 侦听端口 6)根据您的配置修改服务文件 7)更改 Cloudflare 以运行严格模式

第 1 步 - 从 cloudflare 获取 ssl 证书:
Go 到 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

通常,HTTP 的 Headers 不接受非 ASCII 字符。 Urls 必须在生成时正确编码,Redirect 方法不会为您执行此操作。

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

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

这似乎是您的 NGinx 文件和 Cloudflare 的设置方式存在问题。 从配置中,您的设置是

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

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

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

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

您只在端口 80 上运行 nginx 并且没有 ssl,因此$scheme变量将始终为http 请参阅http://nginx.org/r/$scheme

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM