docs(.wiki): iis-migration rollback + post-mortem + xml-escape concept

Phase 9 — rollback миграции на host-IIS из-за Docker port-loop
(host.docker.internal:80 от traefik container резолвится обратно
в сам traefik через NAT, https.yml http-catchall middleware
отдавал 301 -> TOO_MANY_REDIRECTS). Prod снова через VM.

- iis-migration-2026-05-19-postmortem: 10 ошибок миграции +
  recipe для следующей попытки (backend port НЕ :80, smoke с
  MaximumRedirection 0, тест из НЕ-LAN, parallel VM x N часов,
  atomic revert plan)
- webconfig-password-xml-escape: новая gotcha — & в conn-string
  пароле требует & в Web.config (XML reserved char)
- iis-host-migration-2026-05-19: Phase 9 rollback chronology +
  что осталось на хосте inert
- snolla-recovery-vm: статус -> active prod (обратно)
- windows-recovery-host: host IIS sites -> inert artifacts
- recovery-architecture-snapshot: chain снова через VM,
  traefik backends восстановлены из .bak-phase3

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 15:08:07 +03:00
parent ae56813c8d
commit 2d307f2dd0
3 changed files with 327 additions and 43 deletions

View File

@@ -0,0 +1,71 @@
---
title: Web.config — XML escape для спецсимволов в connection-string паролях
type: concept
tags: [iis, webconfig, encoding, xml, gotcha]
sources: [../sources/iis-host-migration-2026-05-19.md]
updated: 2026-05-19
---
# Web.config: XML-escape для `&` (и других reserved chars) в пароле
## Симптом
После patch Web.config с новым connection-string'ом ASP.NET-сайт отдаёт **HTTP 500** на любой запрос. В Event Viewer / IIS logs — `System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize` или `Unrecognized escape sequence`. На уровне XML парсера — error при чтении Web.config.
## Корень
`Web.config` — это **XML-документ**. Атрибуты в нём (`<add connectionString="..." />`) проходят через XML-парсер до того, как .NET runtime увидит сам connection string. Если в пароле есть **XML-зарезервированный символ**, парсер ломается.
XML reserved chars (в значениях атрибутов):
| Символ | XML-entity escape | Когда обязателен |
|---|---|---|
| `&` | `&amp;` | **всегда** (в attribute value и в text content) |
| `<` | `&lt;` | **всегда** |
| `"` | `&quot;` | если значение в `"..."` (наш кейс — атрибуты обычно в двойных кавычках) |
| `'` | `&apos;` | если значение в `'...'` |
| `>` | `&gt;` | формально не обязателен, но safer |
В именно нашем кейсе из [[iis-host-migration-2026-05-19]]: пароль `^I9D)LB)DK)8J#xBDG$t}W&_ioaT!M!LF` содержит `&` — XML-парсер начинал интерпретировать `&_ioaT...` как entity reference (`&_ioaT;` — невалидное имя entity) → exception → IIS 500.
## Правильный способ
```xml
<!-- WRONG (literal &) -->
<add name="MoreThenCmsEntities"
connectionString="...Password=^I9D)LB)DK)8J#xBDG$t}W&_ioaT!M!LF;..."
providerName="System.Data.SqlClient" />
<!-- RIGHT (& -> &amp;) -->
<add name="MoreThenCmsEntities"
connectionString="...Password=^I9D)LB)DK)8J#xBDG$t}W&amp;_ioaT!M!LF;..."
providerName="System.Data.SqlClient" />
```
После XML-парсинга .NET runtime получит литеральный `&` в значении атрибута и передаст в SqlConnection — там пароль уже текст, всё ок.
## Что НЕ требует escape
- `^`, `$`, `(`, `)`, `{`, `}`, `[`, `]`, `*`, `+`, `?`, `\`, `/`, `.`, `,`, `;`, `:`, `=`, `#`, `@`, `%`, `!`, `~`, `|` — все безопасны в XML attribute value.
- Особое: `;` в пароле в ADO.NET conn-string'е требует обёртки пароля в `'...'` или `"..."` внутри connection-string'а — но это отдельная история.
## PowerShell-подсказка для patch
При программной замене conn-string'а**сразу escape `&` в значение**, не оставляй на потом:
```powershell
# 💻 Windows host
$plainPassword = '^I9D)LB)DK)8J#xBDG$t}W&_ioaT!M!LF'
$xmlSafePassword = $plainPassword -replace '&', '&amp;'
# и потом подставлять $xmlSafePassword в Web.config
# или комбинированный escape всех 5 reserved chars:
function Xml-EscapeAttr($s) {
$s -replace '&','&amp;' -replace '<','&lt;' -replace '>','&gt;' -replace '"','&quot;' -replace "'",'&apos;'
}
```
## Связанные паттерны
- [[cms-config-rewrite-pattern]] — UTF-8 BOM ловушка при `Set-Content` без `-Encoding utf8` (другая XML/IIS гнойная тема).
- При генерации паролей для DB-логинов CMS — лучше **запретить `&`, `<`, `"`** в генераторе, чтобы не словить эту проблему в будущем (особенно при автоматизированных patches Web.config через CI).