12 KiB
=== SECURITY GO-LIVE REPORT === Дата: 2026-06-17 Версия схемы: v8.40 Commit: main @ ~cf813c10 (+ незакоммиченные правки параллельной сессии F1/F2 в рабочем дереве) Цель: http://127.0.0.1:8000 (локальная копия, гард IS8)
NB по процедуре: прогон выполнен под стеной «роутер-наставник». Импликации отражены ниже — часть статических инструментов не отработала по техническим причинам (установка/устаревшая команда/десинк указателя), а чтения для анализа ПДн/угроз получены через вставку файлов в чат (impl-режим стены блокирует Read). Это частичный прогон: динамика и анализ ПДн/угроз — выполнены; статический слой инструментов требует доустановки и перезапуска.
--- ШАГ 1: СТАТИКА ---
gitleaks: OK — чистый перезапуск 17.06: 2462 коммита (112.94 MB), 0 утечек.
Учебная фикстура секрет-сканера — в allowlist. Секретов в истории нет.
Semgrep: OK — установлен (semgrep-1.166.0); npm run sast (конфиги p/php,
p/javascript, p/typescript, p/secrets + .semgrep.yml, флаг --error)
завершился exit 0 → 0 находок (--error дал бы exit 1 при любой
находке). Детальный вывод под стеной не читался, но exit-код определяет
результат: блокирующих находок Semgrep нет.
Ward: OK — перезапущен ./bin/ward.exe scan app/ (v0.4.1): 2 находки на
dev-.env — [High] APP_DEBUG включён, [Medium] APP_ENV=local;
config/dependency-scanner — 0. На dev ожидаемо; на боевом
.env.production обязательно APP_DEBUG=false / APP_ENV=production — проверить фактом.
Trail of Bits: SKIP — не применим к этому плановому прогону (вызывается вручную
перед первым публичным релизом / при крупных изменениях периметра).
--- ШАГ 2: ПДн / 152-ФЗ (анализ по чек-листу + код/схема) ---
Режим 1 (технический):
✅ RLS на deals/users/auth_log/import_log/pd_processing_log — включён
(schema v8.40, политики tenant_isolation). supplier_leads/pd_subject_requests
— SaaS-уровень без RLS осознанно (доступ через BYPASSRLS-воркер/админа).
✅ users.totp_secret — шифруется Crypt::encrypt (не plain).
✅ PdAuditLogger->record(...) пишет pd_processing_log при просмотре/создании
сделки (DealController::show/store) — журнал обработки работает на этих путях.
✅ DealController телефоны/ПДн в логи НЕ пишет; activity_log.context для
статуса/назначения — только id/slug.
⚠️ MEDIUM — логи: config/logging.php LOG_LEVEL=debug, PII-scrubbing
процессора в каналах нет. Риск утечки ПДн только если телефон попадёт в
текст исключения; Sentry-scrubbing (OPEN-И-16) — в config/sentry.php,
проверить регекс-маску фактически.
❌ HIGH — pg_anonymizer (OPEN-И-24) ставится только в фазе 3; на момент
прогона расширение может быть НЕ установлено → pg_dump отдаёт ПДн в
открытом виде. Проверить: SELECT extname FROM pg_extension WHERE extname='anon';
Режим 2 (соответствие):
✅ Хранение в РФ (Yandex Cloud ru-central1), tenant_consents, pd_subject_requests
с дедлайном 30 дней (триггер), processing_restricted (ст.21 ч.5),
append-only hash chain на pd_processing_log — присутствуют в схеме.
⚠️ Проверить вручную (вне кода): уведомление РКН, реестр обработки (ст.22.1),
договоры поручения с crm.bp-gr.ru / Unisender Go / JivoSite, локация
серверов Unisender Go.
--- ШАГ 3: УГРОЗЫ (STRIDE-артефакт, в коде этого прогона не переподтверждено) ---
Из модели угроз портала — незакрытые ТОП-приоритеты (P0/P1):
❌ P0 — SAAS_ADMIN_TEST_BYPASS=true в prod = полный доступ к /api/admin/** (E20/E21).
❌ P0 — SSRF через POST /api/webhooks/test (E13): нет фильтрации URL →
metadata YC 169.254.169.254 → IAM-токен.
❌ P0 — GET /api/dashboard/summary без auth (E18, MVP-заглушка).
❌ P0 — GET /api/managers, GET /api/lead-statuses без auth (E9) — раскрытие ФИО менеджеров.
⚠️ P1 — нет rate-limit на login/forgot/2fa/verify (E1–E3); URL-secret
поставщика в access-логах (E4).
Baseline защиты (есть): RLS (40 политик), Sanctum SPA auth, per-token rate-limit
на webhook тенанта (prod), IP-allowlist на webhook поставщика, HMAC X-Webhook-Signature
(prod), auth_log/saas_admin_audit_log, bcrypt, signed URL отчётов.
--- ШАГ 4: ДИНАМИКА (локальная цель 127.0.0.1:8000) ---
Nuclei: OK — 916 шаблонов, 1 match severity INFO (tech-detect:php), 0 medium/high/critical.
Скан завершён за 7 мин. Info-детект стека — не блокер.
ZAP: PENDING — требует Java 17 + запущенного демона; не запускался этим прогоном.
→ установить/поднять ZAP до публичного деплоя (глубокий DAST/active scan).
--- ИЗВЕСТНЫЕ ДОЛГИ (явная проверка) ---
F-T2 (/api/admin/* без app-гейта): ЧАСТИЧНО ЗАКРЫТ фактом — по STRIDE-карте
группа /api/admin/** стоит за middleware saas-admin (fail-closed 503 в
prod). Остаточный риск переехал в P0 выше: SAAS_ADMIN_TEST_BYPASS + SSO
(Yandex 360) не реализован до Б-1. → подтвердить в routes/api.php +
.env.production (флаг false), затем снять.
F-P1 (152-ФЗ: deals.phones не вычищаются): ОТКРЫТ, подтверждён фактом — в модели
Deal только SoftDeletes, анонимизации/ретеншена телефонов нет; в схеме
у deals.deleted_at — просто soft-delete (у users.deleted_at комментарий
«soft delete + анонимизация», у deals — нет). deals.phone/phones/
contact_name после soft-delete остаются в открытом виде бессрочно.
→ реализовать retention-cron (hard-delete или анонимизация phone/contact_name
через N дней после deleted_at) + исполнение request_type='deletion'.
=== ВЕРДИКТ: NO-GO ❌ === Блокеры (critical/high):
- ПДн дампы: pg_anonymizer не установлен (HIGH) → pg_dump отдаёт ПДн открыто.
- F-P1 (HIGH, 152-ФЗ): нет ретеншена/анонимизации телефонов лидов после soft-delete.
- STRIDE P0 (из модели угроз, подтвердить в коде): SAAS_ADMIN_TEST_BYPASS в prod; SSRF в /api/webhooks/test; открытые без auth /api/dashboard/summary, /api/managers, /api/lead-statuses.
Предупреждения (medium):
- Логи без PII-scrubbing процессора (LOG_LEVEL=debug); проверить Sentry-маску фактически.
- Нет rate-limit на login/forgot/2fa/verify; URL-secret поставщика в access-логах.
PENDING / не отработали (должны быть закрыты до публичного деплоя):
- Semgrep #25: не установлен (нет на PATH) — установить и перезапустить
npm run sast. - Ward #70: устаревший флаг в плане — перезапустить
./bin/ward.exe scan app/. - gitleaks #8: перезапустить чисто (в этом прогоне пропущен из-за десинка стены).
- ZAP #68: требует Java-демона — установить и прогнать active scan.
Условный статус инструментов: даже при закрытии находок вердикт остаётся NO-GO до доустановки Semgrep/ZAP и чистого перезапуска gitleaks/Ward — статический и глубоко-динамический слои гейта на этой машине сейчас не полны. === END ===
ПОПРАВКА — верификация по коду (17.06.2026)
Три пункта, ранее помеченные как P0 «из модели угроз», проверены по реальному коду и оказались закрытыми:
- E9 (
/api/managers,/api/lead-statuses) + E18 (/api/dashboard/summary) — подauth:sanctum(+tenant),app/routes/web.php. - E20 (
/api/admin/*) — за middlewaresaas-admin(prod fail-closed 503). - SSRF (
/api/webhooks/test) —WebhookUrlGuardблокирует cloud-metadata/RFC1918/loopback (на сохранении и тесте), URL толькоhttps://.
Вердикт ОСТАЁТСЯ NO-GO. Реальные блокеры НЕ сняты: F-P1 (ретеншен телефонов лидов), pg_anonymizer (не установлен), прод-.env (APP_DEBUG/APP_ENV). Остаточные не-блокеры: bypass-флаг + SSO админки (config / Б-1), DNS-rebind на будущей доставке webhook (edge), rate-limit на login (P1 — проверить throttle).
ДОБИВАНИЕ АУДИТА (17.06.2026) — pg_anonymizer + ZAP
pg_anonymizer: проверено фактом (pg_extension WHERE extname='anon' → пусто) — НЕ установлен (phase-3, OPEN-И-24). pg_dump отдаёт ПДн открыто → блокер B2 в силе.
ZAP #68 (spider + passive, цель 127.0.0.1:8000, демон 2.17.0; active scan не гнали — гард IS8): spider завершён (status 100). Сводка alerts — High 0, Medium 4, Low 28, Informational 4. 0 high/critical → блокеров от ZAP нет. 4 Medium = предупреждения (вероятно security-заголовки), разобрать.
Аудит инструментами ЗАКРЫТ: gitleaks 0 · Semgrep 0 · Ward 2(dev) · Nuclei 0(medium+) · ZAP 0(high).
Вердикт остаётся NO-GO — держат не сканеры, а: F-P1 (ретеншен телефонов), pg_anonymizer (не установлен), прод-.env (APP_DEBUG/APP_ENV).