import: merge .wiki/concepts/ from temp prefix into existing dir (history preserved via merge+rename)
This commit is contained in:
71
.wiki/concepts/webconfig-password-xml-escape.md
Normal file
71
.wiki/concepts/webconfig-password-xml-escape.md
Normal 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 | Когда обязателен |
|
||||
|---|---|---|
|
||||
| `&` | `&` | **всегда** (в 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).
|
||||
Reference in New Issue
Block a user