From 5d7a14c7d4ccaffdf6698382f5015f650993e339 Mon Sep 17 00:00:00 2001 From: vitya Date: Tue, 19 May 2026 18:43:03 +0300 Subject: [PATCH] =?UTF-8?q?docs(.wiki,.tasks):=20close=20cms-port-leak-fix?= =?UTF-8?q?=20=E2=80=94=20URL=20Rewrite=20serverVariables=20=D0=BD=D0=B0?= =?UTF-8?q?=20host=20IIS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port :8089/:4443 утечка в admin URLs закрыта. URL Rewrite 2.1 + apphost allowedServerVariables (HTTPS/SERVER_PORT/SERVER_PORT_SECURE) + Web.config rule на X-Forwarded-Proto=https → set SERVER_PORT=443/SERVER_PORT_SECURE=1/HTTPS=on ДО того как ASP.NET читает их в Url.SiteRoot(). Лечит все 11 cms (общий site snolla). Path B (traefik http entrypoint :80→:8090) abandoned — Docker Desktop WSL2 NAT quirk на host.docker.internal:80 возвращает 17-byte 301 plain text независимо от traefik internals. Quirk не reproducible на Linux Docker (synology). Side regression: pre-existing customErrors mode="off" lowercase в Web.config пробудился после ASP.NET full-reload (мой rewrite-block edit) — fixed (Off). Outside scope, open: emspb.snolla.com /admin/assets//getList → 500 NullRef в AssetsJsonViewModelBuilder.cs:22 (model null от GetFolderByPath). User подтвердил «только этот site». Зафиксировано в snapshot open issue #8. Co-Authored-By: Claude Opus 4.7 (1M context) --- cms-server-port-leak-fix.md | 174 +++++++++++++++++++++++++++ recovery-architecture-snapshot.md | 3 +- traefik-on-windows-docker-desktop.md | 24 +--- 3 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 cms-server-port-leak-fix.md diff --git a/cms-server-port-leak-fix.md b/cms-server-port-leak-fix.md new file mode 100644 index 0000000..28d29e2 --- /dev/null +++ b/cms-server-port-leak-fix.md @@ -0,0 +1,174 @@ +--- +title: CMS port-leak fix — URL Rewrite serverVariables на host IIS +type: concept +tags: [iis, url-rewrite, traefik, x-forwarded, asp-net, gotcha] +sources: [../sources/iis-host-migration-2026-05-19.md] +updated: 2026-05-19 +--- + +# CMS port-leak fix + +Решение для open issue #1 из [[recovery-architecture-snapshot]] (раньше «X-Forwarded headers не настроены, :4443 leak») и админ-utечки `:8089` обнаруженной 2026-05-19 вечером после attempt 2 host-IIS миграции. Документирует **root cause**, **почему VM работала**, **почему обходной path-B на Windows Docker Desktop невозможен**, и **что в итоге применено**. + +Связано: [[traefik-on-windows-docker-desktop]] Pitfall 5, [[iis-host-migration-2026-05-19]] Phase 10, [[docker-host-loopback-detect]]. + +## Симптом + +Admin URLs формата (после attempt 2 миграции на host-IIS:8089): +- `https://emspb.snolla.com:8089/admin/assets//getList?path=` +- `https://emspb.snolla.com:8089/admin/themes/getImageSizes/` +- `https://emspb.snolla.com:8089/admin/templates/editors.tmpl.html?v=2.006` + +Browser HSTS upgrade'ит `http://...:8089` → `https://...:8089` → TCP open, TLS handshake fails (8089 = plain HTTP) → admin SPA ломается. + +Аналогично, ранее (issue #1) — CMS делал HTTP→HTTPS redirect с `:4443` (traefik external port). + +## Root cause + +`MoreThenCms.Admin\Mis\Web\Mvc\UrlHelpers\UrlHelpers.cs:14-37` `Url.SiteRoot()`: + +```csharp +var port = context.Request.ServerVariables["SERVER_PORT"]; +if (usePort) { + if (port == null || port == "80" || port == "443") port = ""; + else port = ":" + port; +} +var protocol = context.Request.ServerVariables["SERVER_PORT_SECURE"]; +if (protocol == null || protocol == "0") protocol = "http://"; else protocol = "https://"; +var sOut = protocol + context.Request.ServerVariables["SERVER_NAME"] + port + appPath; +``` + +Читает **socket-level** server variables. На IIS site `snolla` binding `*:8089` HTTP → `SERVER_PORT=8089`, `SERVER_PORT_SECURE=0` → формирует `http://emspb.snolla.com:8089` → рендерится в Razor: + +```cshtml +@* C:\sites\snolla\Views\Shared\_Layout.cshtml:229 *@ +mis.siteRoot = '@Url.SiteRoot().Replace("http:", "https:")' + '/admin'; +@* и _LogInLayout.cshtml:156 *@ +mis.siteRoot = '@Url.SiteRoot()'; +``` + +Замена `http:→https:` в Layout была *прошлым* частичным patch'ем — не убирает порт. Десятки .cshtml в admin также используют `Url.SiteRoot()` для inline `