[英].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();
});
但是使用此解决方案,我不会传递标题并丢失一些信息。
那么有人对这种情况有任何解决方案吗?
您的 Startup.cs 文件很好,但您没有为 Kesterl 配置 ssl。
您需要为您的 .net 核心应用程序配置 X.509 ssl 证书
只有反向代理服务器需要 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 通过公共互联网发送未加密的客户数据。
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.