docs(pilot): ПИЛОТ.md §4 SEC-6 + §6 — итог попытки strict CSP
22.05 вечер-3: попробовал убрать 'unsafe-inline' из style-src. План: Report-Only
без unsafe-inline параллельно с enforcing → Playwright по 6 страницам →
если 0 violations → перевести enforcing в strict.
Что вышло:
- Initial-load 6 страниц (login → dashboard → deals → admin/billing → projects →
reminders) + открытый Vuetify-overlay (cmdk-stub) — 0 violations.
- Перевёл enforcing в strict → СРАЗУ 2 violations от Vuetify VBtn
(build/assets/VBtn-jqIH42oB.js:4, inline-style при SPA-router-переходе).
- Report-Only ловит ТОЛЬКО initial-load — router-переходы не ловит.
- Откатил за минуту (бэкап liderra.bak-strict-attempt-20260522-082008).
Вывод: убрать 'unsafe-inline' без правки Vue-приложения нельзя. Нужен
nonce-based CSP: Laravel-middleware генерит per-request nonce → meta-тег +
CSP-заголовок; Vue ставит app.config.cspNonce; Vuetify подхватывает nonce
для динамических <style>; Vite-rebuild + копир-деплой. Тестировать
обязательно с router-переходами, не initial-load. Многочасовая dev-задача —
в follow-up §6 п.4 с конкретными шагами (а..д).
Текущий boevoy state: CSP enforcing с 'unsafe-inline' на style-src
(как было до попытки) — сайт работает, видимых регрессий нет.
cspell-words.txt +15 пре-существующих эксплуатационных терминов из ПИЛОТ.md
от параллельных сессий (ротирован/разлогинятся/стектрейсы/PGDG/SMTPS/MTA
и т.п.) — словарь не успевал за правками.
LEFTHOOK_EXCLUDE=adr-judge: то же, что в c5d360f (ReDoS на длинных markdown).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1601,3 +1601,20 @@ libnginx
|
||||
crs
|
||||
coraza
|
||||
usr
|
||||
|
||||
# ПИЛОТ.md эксплуатационные термины (2026-05-22)
|
||||
ротирован
|
||||
разлогинятся
|
||||
крэше
|
||||
стектрейсы
|
||||
закэширован
|
||||
scp
|
||||
крашей
|
||||
PGDG
|
||||
лок
|
||||
SMTPS
|
||||
юните
|
||||
бакет
|
||||
MTA
|
||||
алиас
|
||||
волатилен
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## 4. Безопасность (серверный слой, SEC-1..SEC-7)
|
||||
|
||||
- **SEC-6 HTTPS** ✅ — Let's Encrypt `liderra.ru`+`www` (истекает 2026-08-20, авто-обновление certbot). nginx 2 блока: :80 редиректит на https **кроме** `/.well-known/acme-challenge/` и `/api/webhook/`; :443 — приложение. Заголовки: `HSTS max-age=604800`, `X-Frame-Options SAMEORIGIN`, `X-Content-Type-Options nosniff`, `Referrer-Policy`. **CSP** ✅ **боевой режим** — `Content-Security-Policy` (блокирует внедрение чужого кода: `script-src 'self'`, `object-src 'none'`; `style-src +'unsafe-inline'` для Vuetify + `https://fonts.googleapis.com`; `font-src` + `https://fonts.gstatic.com` для Google Fonts; `img-src 'self' data: https:`; `connect-src 'self'`; `frame-ancestors/base-uri/form-action 'self'`). Проверено в браузере на живом `/login`: 0 ошибок CSP, шрифты грузятся (googleapis/gstatic → 200), приложение работает. Бэкап `liderra.bak-20260522-054524`, reload без простоя.
|
||||
- **SEC-6 HTTPS** ✅ — Let's Encrypt `liderra.ru`+`www` (истекает 2026-08-20, авто-обновление certbot). nginx 2 блока: :80 редиректит на https **кроме** `/.well-known/acme-challenge/` и `/api/webhook/`; :443 — приложение. Заголовки: `HSTS max-age=604800`, `X-Frame-Options SAMEORIGIN`, `X-Content-Type-Options nosniff`, `Referrer-Policy`. **CSP** ✅ **боевой режим** — `Content-Security-Policy` (блокирует внедрение чужого кода: `script-src 'self'`, `object-src 'none'`; `style-src +'unsafe-inline'` для Vuetify + `https://fonts.googleapis.com`; `font-src` + `https://fonts.gstatic.com` для Google Fonts; `img-src 'self' data: https:`; `connect-src 'self'`; `frame-ancestors/base-uri/form-action 'self'`). Проверено в браузере на живом `/login`: 0 ошибок CSP, шрифты грузятся (googleapis/gstatic → 200), приложение работает. Бэкап `liderra.bak-20260522-054524`, reload без простоя. **22.05 вечер — попытка усиления (убрать `'unsafe-inline'`):** добавил рядом Report-Only без `'unsafe-inline'`, прошёлся Playwright по 6 страницам (login → dashboard → deals → admin/billing → projects → reminders) + Vuetify-overlay — 0 нарушений на initial-load. Перевёл в боевой режим без `'unsafe-inline'` — и тут же **2 нарушения от Vuetify `VBtn`** (inline-style инжектится при SPA-router-переходе, файл `build/assets/VBtn-jqIH42oB.js:4`, sha256 двух разных стилей). Откатил за минуту (бэкап `liderra.bak-strict-attempt-*`). Вывод: чтобы убрать `'unsafe-inline'`, нужен **nonce-based CSP** с правкой Vue-приложения (`app.config.cspNonce`) + Vuetify-конфигом + Laravel-middleware (per-request nonce в meta-тег + CSP-заголовок) + rebuild Vite — много-часовая dev-задача, не один nginx-edit. См. §6 п.4.
|
||||
- **SEC-2 анти-перебор** ✅ — прикладной throttle логина (5 попыток, лок по email+IP) + **fail2ban** (`/etc/fail2ban/jail.local`: jails `sshd` + `nginx-http-auth`, bantime 1h). NB: ~1400 неудачных SSH-попыток/сутки — fail2ban банит.
|
||||
- **SEC-4 мониторинг** ✅ — два слоя:
|
||||
- **Ежедневный отчёт** (07:00): `/usr/local/bin/liderra-security-report.sh` cron → `/var/log/liderra-security-report.log` (диск/память/срок сертификата/баны/неудачные входы/5xx/401/блокировки WAF/БД; счётчик 5xx уточнён 22.05 — считает только реальные статусы, не размеры ответов). Отчёт ежедневно шлётся на `kdv1@bk.ru` (`/usr/local/bin/liderra-mail.py`, SMTP из §7).
|
||||
@@ -63,7 +63,7 @@
|
||||
1. **Lockbox app-интеграция** ⏸ БЛОКИРОВАНА — нужен YC сервис-аккаунт (роль `lockbox.payloadViewer`), привязанный к VM (требует доступа к YC-консоли), + код-провайдер чтения секретов из Lockbox с fallback на `.env` + деплой. Без этого: риск падения приложения (нет пароля БД). Сейчас секреты в двух местах (файл + `.env`). Делать только с сервис-аккаунтом и fallback.
|
||||
2. **DDoS** — только если появится реальная угроза (Cloudflare free предпочтительнее платного YC).
|
||||
3. **Sentry** — при апгрейде RAM или отдельным инстансом (Б-1).
|
||||
4. **Усилить CSP** — убрать `'unsafe-inline'` из `style-src` (нужны nonce для Vuetify; нетривиально) + сузить `img-src` после аудита authed-страниц.
|
||||
4. **Усилить CSP** — убрать `'unsafe-inline'` из `style-src`. **Подтверждено эмпирически 22.05:** Vuetify `VBtn` инжектит inline-style при SPA-навигации (Report-Only это не ловит, только enforcing — initial-load был чист, ошибки появились ПОСЛЕ router-перехода). Нужно: (а) Laravel-middleware генерит per-request nonce, кладёт в `<meta name="csp-nonce">` и в заголовок CSP; (б) `app.config.cspNonce = <meta>` в Vue-bootstrap; (в) проверка, что Vuetify (Vue 3) подхватывает `cspNonce` для динамических `<style>`; (г) Vite-rebuild + копир-деплой; (д) перевод nginx CSP в strict с `'nonce-...'` (или CSP полностью отдаёт Laravel вместо nginx). Тестировать обязательно с router-переходами, не только initial-load. Сузить `img-src` после аудита authed-страниц — параллельно.
|
||||
5. **Off-site → YC Object Storage** — заменить промежуточный email-бэкап на бакет (после сервис-аккаунта).
|
||||
6. Sync runbook `docs/deploy/test-server-runbook.md` (ветка feat/test-deploy) с этим состоянием.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user