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>
72 lines
4.1 KiB
Markdown
72 lines
4.1 KiB
Markdown
---
|
||
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 | Когда обязателен |
|
||
|---|---|---|
|
||
| `&` | `&` | **всегда** (в attribute value и в text content) |
|
||
| `<` | `<` | **всегда** |
|
||
| `"` | `"` | если значение в `"..."` (наш кейс — атрибуты обычно в двойных кавычках) |
|
||
| `'` | `'` | если значение в `'...'` |
|
||
| `>` | `>` | формально не обязателен, но 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 (& -> &) -->
|
||
<add name="MoreThenCmsEntities"
|
||
connectionString="...Password=^I9D)LB)DK)8J#xBDG$t}W&_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 '&', '&'
|
||
# и потом подставлять $xmlSafePassword в Web.config
|
||
|
||
# или комбинированный escape всех 5 reserved chars:
|
||
function Xml-EscapeAttr($s) {
|
||
$s -replace '&','&' -replace '<','<' -replace '>','>' -replace '"','"' -replace "'",'''
|
||
}
|
||
```
|
||
|
||
## Связанные паттерны
|
||
|
||
- [[cms-config-rewrite-pattern]] — UTF-8 BOM ловушка при `Set-Content` без `-Encoding utf8` (другая XML/IIS гнойная тема).
|
||
- При генерации паролей для DB-логинов CMS — лучше **запретить `&`, `<`, `"`** в генераторе, чтобы не словить эту проблему в будущем (особенно при автоматизированных patches Web.config через CI).
|