fix(nginx): use X-Forwarded-Proto header for proper protocol forwarding#443
fix(nginx): use X-Forwarded-Proto header for proper protocol forwarding#443myml wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the Nginx configuration to use the $http_x_forwarded_proto variable for the X-Forwarded-Proto header across several location blocks. The review feedback highlights a security risk regarding header spoofing and potential functional regressions if the header is absent. It is recommended to implement a fallback to the $scheme variable. Furthermore, the reviewer identified missing X-Forwarded-For and X-Real-IP headers in several blocks, which should be added to ensure consistent upstream auditing and client identification.
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
| proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; |
There was a problem hiding this comment.
Blindly trusting the X-Forwarded-Proto header from the client introduces a security risk (header spoofing) and can lead to functional issues if the header is missing.
- Security Risk: A client can spoof this header to trick the upstream into believing the connection is secure (HTTPS) when it is not. This is particularly dangerous for OAuth2 flows where protocol-sensitive redirects are generated.
- Functional Regression: If Nginx is accessed directly (e.g., in local development or a non-proxied environment),
$http_x_forwarded_protowill be empty, resulting in an empty header being sent to the upstream. This may cause the backend to fail or default to an incorrect protocol.
A more robust approach is to use a map in the http block to fall back to $scheme if the header is empty. Since this is a template and the http block is not visible, the following inline logic provides a safer fallback.
set $proxy_x_forwarded_proto $scheme;
if ($http_x_forwarded_proto) {
set $proxy_x_forwarded_proto $http_x_forwarded_proto;
}
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
| proxy_set_header Host $host; | ||
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
| proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; |
There was a problem hiding this comment.
This location is missing the X-Forwarded-For header, which is inconsistent with the /api/ location and important for upstream auditing and rate limiting. Additionally, the X-Forwarded-Proto header should implement a fallback to $scheme to prevent spoofing and issues in non-proxied environments.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $proxy_x_forwarded_proto $scheme;
if ($http_x_forwarded_proto) {
set $proxy_x_forwarded_proto $http_x_forwarded_proto;
}
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
| proxy_set_header Host $host; | ||
| proxy_set_header X-Real-IP $remote_addr; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
| proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; |
There was a problem hiding this comment.
This location is missing the X-Forwarded-For header. It should also implement the X-Forwarded-Proto fallback logic to maintain consistency and security across all proxied endpoints, especially for authentication-related paths.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $proxy_x_forwarded_proto $scheme;
if ($http_x_forwarded_proto) {
set $proxy_x_forwarded_proto $http_x_forwarded_proto;
}
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
| proxy_pass ${SKILLHUB_API_UPSTREAM}; | ||
| proxy_set_header Host $host; | ||
| proxy_set_header X-Forwarded-Proto $scheme; | ||
| proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; |
There was a problem hiding this comment.
The /.well-known/ location is missing both X-Real-IP and X-Forwarded-For headers. It should also implement the X-Forwarded-Proto fallback logic to ensure proper client identification and security consistency.
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $proxy_x_forwarded_proto $scheme;
if ($http_x_forwarded_proto) {
set $proxy_x_forwarded_proto $http_x_forwarded_proto;
}
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
Replace $scheme with $http_x_forwarded_proto in proxy headers to correctly forward the original client protocol when behind a reverse proxy or load balancer. This fixes OAuth2 authentication issues where redirects would use the wrong protocol scheme.
dongmucat
left a comment
There was a problem hiding this comment.
当前改动会修复外层 TLS 终止代理后 OAuth {baseUrl} 被算成 http 的问题,方向是对的;但这里不能在默认模板里无条件信任客户端传入的 X-Forwarded-Proto。
web/nginx.conf.template 现在先用 $http_x_forwarded_proto 覆盖 $scheme,再把结果转发给 /api/、/oauth2/、/login/oauth2/ 和 /.well-known/ 后端请求。release compose 默认会把 web 容器作为公网入口暴露,而后端又启用了 server.forward-headers-strategy: framework,部分下载/cookie 安全判断也直接依赖 X-Forwarded-Proto。这样直连客户端只要伪造 X-Forwarded-Proto: https,就能改写后端对请求协议安全性的判断。
建议把“信任上游 forwarded proto”做成显式部署选择,或只在可信外层代理已经清洗/覆盖该 header 的场景启用;默认直连模式应继续使用 $scheme。同时最好补一条部署级/模板级验证:直连 web 时客户端自带的 X-Forwarded-Proto 不会改变传给后端的 proto,可信代理场景才允许转发 https。
Replace $scheme with $http_x_forwarded_proto in proxy headers to correctly
forward the original client protocol when behind a reverse proxy or load
balancer. This fixes OAuth2 authentication issues where redirects would use
the wrong protocol scheme.