From 20c3fa91fb5a7ac89d7b3bab0300f530722c8871 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Sat, 6 Jun 2026 01:52:38 +0000 Subject: [PATCH] =?UTF-8?q?refactor(https):=20=E5=8D=8F=E8=AE=AE=E8=AF=86?= =?UTF-8?q?=E5=88=AB=E4=B8=8B=E6=B2=89=E5=88=B0=20nginx=EF=BC=8CTrustProxi?= =?UTF-8?q?es=20=E5=8F=AA=E4=BF=A1=20X-Forwarded-Proto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nginx 经 APP_SCHEME 环境变量(envsubst 模板)统一控制 X-Forwarded-Proto - TrustProxies 信任内网代理但仅采信 X-Forwarded-Proto,防 Host 注入 - 移除 WebApi 中间件的硬编码强制 https - getSchemeAndHost 优先用当前请求 scheme/host,保留非请求上下文兜底 - cmd https 切换后改用 compose up -d 重建 nginx 容器使 envsubst 生效 Co-Authored-By: Claude Opus 4.8 (1M context) --- app/Http/Middleware/TrustProxies.php | 9 +++++-- app/Http/Middleware/WebApi.php | 8 ------ app/Module/Base.php | 7 +++++ cmd | 2 +- docker-compose.yml | 4 ++- docker/nginx/default.conf | 38 +++++++++++++++++++++++----- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index a3b6aef90..d9cad9fe5 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/app/Http/Middleware/TrustProxies.php @@ -10,14 +10,19 @@ class TrustProxies extends Middleware /** * The trusted proxies for this application. * + * PHP(Swoole)只在内网被 nginx 访问,外部无法直连,故信任内网代理。 + * * @var array|string|null */ - protected $proxies; + protected $proxies = '*'; /** * The headers that should be used to detect proxies. * + * 只采信 X-Forwarded-Proto:nginx 已用 $the_scheme 覆盖该头(值由 nginx 控制), + * 据此让 url() 实时跟随 https;host/for 一律不信,避免 Host 注入与 IP 伪造。 + * * @var int */ - protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB; + protected $headers = Request::HEADER_X_FORWARDED_PROTO; } diff --git a/app/Http/Middleware/WebApi.php b/app/Http/Middleware/WebApi.php index 3c3028caf..47a6890e6 100644 --- a/app/Http/Middleware/WebApi.php +++ b/app/Http/Middleware/WebApi.php @@ -25,14 +25,6 @@ class WebApi RequestContext::set('start_time', microtime(true)); RequestContext::set('header_language', $request->header('language')); - // 强制 https - $APP_SCHEME = env('APP_SCHEME', 'auto'); - if (in_array(strtolower($APP_SCHEME), ['https', 'on', 'ssl', '1', 'true', 'yes'], true)) { - $request->server->set('HTTPS', 'on'); - $request->headers->set('X-Forwarded-Proto', 'https'); - $request->setTrustedProxies([$request->getClientIp()], $request::HEADER_X_FORWARDED_PROTO); - } - // 更新请求的基本URL RequestContext::updateBaseUrl($request); diff --git a/app/Module/Base.php b/app/Module/Base.php index e3e7928b7..25a71aec0 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -848,6 +848,13 @@ class Base */ public static function getSchemeAndHost() { + // 优先用当前请求的协议+主机:getScheme() 会经 TrustProxies 采信 X-Forwarded-Proto, + // 从而正确识别 https;host 取自 Host 头(不信 X-Forwarded-Host,避免 Host 注入) + $request = request(); + if ($request && $request->getHttpHost()) { + return $request->getSchemeAndHttpHost(); + } + // 非请求上下文(Task/命令行等)的兜底 $scheme = isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? 'https://' : 'http://'; return $scheme.($_SERVER['HTTP_HOST'] ?? ''); } diff --git a/cmd b/cmd index 96e41a906..c30d4c5c0 100755 --- a/cmd +++ b/cmd @@ -882,7 +882,7 @@ case "$1" in else https_auto fi - restart_php + $COMPOSE up -d ;; "artisan") shift 1 diff --git a/docker-compose.yml b/docker-compose.yml index 69451fe2f..6ab04c3fe 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,8 +42,10 @@ services: ports: - "${APP_PORT}:80" - "${APP_SSL_PORT:-0}:443" + environment: + APP_SCHEME: "${APP_SCHEME:-auto}" volumes: - - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf + - ./docker/nginx/default.conf:/etc/nginx/templates/default.conf.template - ./:/var/www healthcheck: test: ["CMD", "curl", "-f", "http://localhost/health"] diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf index 24397ab8f..b20d10ab1 100644 --- a/docker/nginx/default.conf +++ b/docker/nginx/default.conf @@ -1,23 +1,47 @@ +map $host $app_scheme_raw { + default "${APP_SCHEME}"; +} + +map $app_scheme_raw $force_https { + "https" 1; + "on" 1; + "ssl" 1; + "1" 1; + "true" 1; + "yes" 1; + default 0; +} + map $http_upgrade $connection_upgrade { default upgrade; - '' close; + "" close; } + map $http_host $this_host { - "" $host; + "" $host; default $http_host; } -map $http_x_forwarded_proto $the_scheme { - default $http_x_forwarded_proto; - "" $scheme; -} + map $http_x_forwarded_host $the_host { + "" $this_host; default $http_x_forwarded_host; - "" $this_host; } + +map $http_x_forwarded_proto $auto_scheme { + "" $scheme; + default $http_x_forwarded_proto; +} + +map $force_https $the_scheme { + 1 https; + default $auto_scheme; +} + upstream service { server php:20000 weight=5 max_fails=3 fail_timeout=30s; keepalive 16; } + server { listen 80;