From 74d493cd12131317e44173759e44b61eb52dbb1b Mon Sep 17 00:00:00 2001 From: Mikhail Yenuchenko Date: Wed, 15 Jul 2026 23:59:17 +0300 Subject: [PATCH] docs: record decisions for A.2 (security headers) and A.5 (setup-link stdout) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A.2: headers emitted from the panel, not reverse-proxy — keep proxy config minimal and hard to break, push complexity into the service. A.5: keep stdout as the base setup-link delivery per spec; document the /data/setup-token file as a more secure alternative for centralized-logging setups. --- docs/implementation-plan.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md index c4daf0d..f95fbdf 100644 --- a/docs/implementation-plan.md +++ b/docs/implementation-plan.md @@ -23,10 +23,10 @@ ### A. Безопасность — hardening сверх обязательного 7.6 1. **Rate-limit за обратным прокси кеился по `RemoteAddr`** ([internal/web/web.go](../internal/web/web.go) `clientIP`). **Решено:** вариант (б) — парсить `X-Forwarded-For`, но только когда прямой peer (`RemoteAddr`) входит в `TRUSTED_PROXY_CIDR` (список CIDR через запятую, env, по умолчанию пусто); тогда используется последний элемент XFF (адрес, добавленный самим доверенным прокси). Без настройки `TRUSTED_PROXY_CIDR` поведение не меняется (лимит по `RemoteAddr`, глобальный за прокси). См. `deploy/.env.example`. -2. **Нет security-заголовков ответа** — панель не шлёт `Strict-Transport-Security`, `Content-Security-Policy`, `X-Frame-Options`/`frame-ancestors`, `X-Content-Type-Options: nosniff`, `Referrer-Policy`. XSS уже закрыт автоэкранированием `html/template` (7.6.7), CSRF — `SameSite=Lax`, но заголовки — дешёвый второй эшелон (clickjacking, downgrade, sniffing). **Вопрос:** эмитить их из панели (единый мидлварь, ~10 строк) или переложить на reverse-proxy и задокументировать в `deploy/`? Рекомендация — минимальный набор из панели (HSTS/nosniff/`frame-ancestors 'none'`/строгий CSP `default-src 'self'`), т.к. панель знает свою модель контента, а прокси у всех разный. +2. **Нет security-заголовков ответа** — панель не шлёт `Strict-Transport-Security`, `Content-Security-Policy`, `X-Frame-Options`/`frame-ancestors`, `X-Content-Type-Options: nosniff`, `Referrer-Policy`. XSS уже закрыт автоэкранированием `html/template` (7.6.7), CSRF — `SameSite=Lax`, но заголовки — дешёвый второй эшелон (clickjacking, downgrade, sniffing). **Решено:** эмитить из панели (единый мидлварь, ~10 строк), не перекладывать на reverse-proxy. Общий принцип: всю сложность стараемся держать в сервисе, а конфигурация reverse-proxy должна оставаться максимально простой, чтобы её было сложно сломать неудачной правкой. 3. **CSRF — только `SameSite=Lax`, без токенов.** Достаточно для современных браузеров (все мутации — POST, все GET read-only), но не защищает при downgrade до старого браузера/особых прокси и не даёт защиты на уровне «per-request». **Вопрос:** считать `SameSite=Lax` достаточным для single-admin панели (моя рекомендация — да) или добавить double-submit CSRF-токен. 4. **Cookie без префикса `__Host-`.** Сейчас `selfpost_session` (`Secure`/`HttpOnly`/`SameSite=Lax`/`Path=/`). Префикс `__Host-` дал бы браузерный гарант «только HTTPS, только этот хост, без Domain». Мелочь, но бесплатная. **Вопрос:** переименовать (учесть dev-режим `PANEL_COOKIE_SECURE=false` — `__Host-` требует `Secure`, т.е. только когда secure включён). -5. **Setup-ссылка печатается в stdout контейнера.** По ТЗ (7.6.1) — так и задумано, но если логи контейнера уезжают в агрегатор, токен там осядет на 10 минут. Файл `/data/setup-token` (0600) — альтернатива. Оставить как есть (по ТЗ), но **отметить в README**, что для сред с централизованными логами предпочтителен файл. +5. **Setup-ссылка печатается в stdout контейнера.** По ТЗ (7.6.1) — так и задумано, но если логи контейнера уезжают в агрегатор, токен там осядет на 10 минут. Файл `/data/setup-token` (0600) — альтернатива. **Решено:** базовый вариант — stdout (по ТЗ), без изменений в коде. В пользовательской документации отдельно осветить этот вопрос и предложить более защищённые альтернативы (например, файл `/data/setup-token`) — для тех, у кого логи контейнера уезжают в централизованный агрегатор. 6. **Нет 2FA / смены пароля админа / нескольких админов из UI.** ТЗ этого не требует (один админ, secret-link). Смена пароля сейчас — только пересоздание состояния. **Решено:** добавить раздел настроек аккаунта (логин + пароль) — см. Фазу 12 ниже. 2FA и мульти-админ остаются явно 2.x/вне объёма. ### B. Надёжность и эксплуатация