import-stage: .wiki/concepts/ via split (temp prefix for merge into existing dir)

git-subtree-dir: .tmp-concepts
git-subtree-mainline: 98bcc37d32
git-subtree-split: c727aaa1b6
This commit is contained in:
2026-05-21 13:46:51 +03:00
24 changed files with 2628 additions and 0 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).