Аудит безопасности
Статус: Развёрнуто в production
URL платформы: https://ziex-tryon.com
Все 41 проблема безопасности устранена или осознанно отложена. 507 тестов. Покрытие ≥97%.
Обзор¶
Платформа TryOn SaaS — это B2B-сервис виртуальной примерки одежды, развёрнутый по адресу ziex-tryon.com. В мае 2026 года было выявлено 41 проблема безопасности и качества кода — все были устранены или осознанно отложены с письменным обоснованием. Платформа теперь работает с 507 автоматическими тестами, покрытием кода более 97%, полной наблюдаемостью через метрики Prometheus и три дашборда Grafana, а также автоматическим CI/CD-деплоем с верификацией состояния после развёртывания.
Что было построено¶
Основная платформа¶
- API виртуальной примерки — Бизнесы интегрируются через REST API. Покупатели отправляют два изображения; AI возвращает результат примерки за 15–30 секунд.
- Мультитенантный биллинг — У каждого клиента есть аккаунт, месячный тариф, API-ключи и опциональные вебхук-коллбэки.
- Клиентский портал — Самообслуживание: история задач, использование vs квота, управление вебхуками.
- Встраиваемый виджет — Один тег
<script>, автоопределение продуктов, изоляция через Shadow DOM.
Устранение проблем безопасности — 41 находка¶
По категориям¶
| Категория | Находок | Статус |
|---|---|---|
| Аутентификация и управление доступом | 8 | Все устранены |
| Валидация ввода и инъекции | 7 | Все устранены |
| Инфраструктура и конфигурация | 14 | Устранены + 3 отложены по решению |
| Корректность фронтенда | 7 | Все устранены |
| Наблюдаемость и мониторинг | 5 | Устранены в Фазе 2 |
Закрытые ключевые риски¶
| Риск | До | После |
|---|---|---|
| Инъекция вредоносных URL через вебхуки | Без валидации | Заблокировано: приватные IP, loopback, cloud metadata. DNS-проверка при регистрации. |
| Неограниченное злоупотребление API | Нет лимита по IP | 30 запросов/мин по IP |
| Брутфорс паролей | Нет блокировки | 5 попыток, блокировка 15 мин по IP + email |
| Кросс-клиентское чтение задач | Без изоляции по тенантам | Каждый поиск статуса фильтруется по client_id |
| Открытые данные мониторинга | Метрики Prometheus публично доступны | Заблокировано на nginx (403) |
| Открытые внутренние порты | БД/Redis/Prometheus доступны извне | Production закрывает все внутренние порты |
| Небезопасная загрузка изображений | Нет защиты от decompression bomb | Проверка магических байтов, лимит 16.7М пикселей, удаление EXIF |
| Перечисление пользователей по таймингу | Тайминг входа раскрывал наличие пользователя | Константное время сравнения на всех путях кода |
| Зависшие задачи воркера | Нет таймаута поллинга | Потолок 600 сек; устаревшие задачи автоматически переводятся в failed через 15 мин |
| SQL-инъекции | f-string SQL в 7 местах | Всё параметризовано |
Текущее состояние платформы¶
| Показатель | Значение |
|---|---|
| Автоматические тесты | 507+ в 26 тестовых файлах |
| Покрытие кода | ≥97% |
| Открытые проблемы безопасности | 0 |
| Мониторинг | Prometheus + Grafana (3 авто-подготовленных дашборда) |
| Алертинг | Telegram (здоровье воркера, частота ошибок, доступность БД/Redis) |
| Резервное копирование | Ежедневное автоматическое, хранение 30 дней |
| CI/CD | lint → test → build → deploy при успехе CI |
| TLS | Cloudflare proxy, HSTS, TLSv1.2+ |
Приёмка аудита
Аудит Package 10 завершён 2026-05-18. Все 44 шага E2E-браузерного тестирования прошли (Admin UI + Portal + Embed). Все проверки готовности к production прошли (health, security headers, nginx, docker-compose.prod.yml, backup, deploy.sh). Ноль предупреждений ruff.
Осознанно отложенные пункты¶
Эти пункты были оценены и явно отложены — они не являются открытыми проблемами.
| Пункт | Обоснование | Остаточный риск |
|---|---|---|
| Восстановление пароля / email-recovery | Требует email-провайдер. Восстановление администратора через прямой доступ к БД достаточно на текущем масштабе. | Низкий |
| Самообслуживание API-ключей на портале | Управляемые администратором ключи безопасны. Самообслуживание — улучшение UX для Фазы 3. | Нет |
| Предподписанные URL загрузки S3 | Текущий flow с base64 работает на данных объёмах. | Нет |
| Rate limiting смены пароля | Окно токена доступа 15 мин ограничивает поверхность атаки. | Очень низкий |
| Горизонтальное масштабирование GPU-воркера на K8s | Один сервер справляется с текущей нагрузкой. | Нет |
Отложено ≠ игнорируется
Каждый отложенный пункт имеет письменное обоснование и будет пересмотрен при наступлении условия-триггера (например, email-recovery — при добавлении email-провайдера; K8s — когда нагрузка потребует).
Реестр технического долга¶
Это известные ограничения на уровне кода, которые не блокируют запуск, но должны быть устранены в ближайших спринтах.
| Проблема | Влияние | Усилия |
|---|---|---|
avg_latency_ms не пересчитывается при CONFLICT |
Дашборд использования показывает задержку первой задачи клиента, не скользящее среднее | Низкие — SQL-формула |
Admin webhook CRUD: допущение user.id == client.id |
Второй admin-пользователь без соответствующей записи Client получает 404 на все операции с вебхуками | Низкие — исправление запроса |
Счётчик Prometheus TRYON_COMPLETED не инкрементируется |
Счётчик завершений на дашборде всегда равен нулю | Низкие — один вызов .inc() в воркере |
| Node.js 20 EOL июнь 2026 | Сборка фронтенда использует неподдерживаемую среду выполнения после июня 2026 | Низкие — обновить базовый образ до node:22-alpine |
CI diff использует HEAD~1 |
Обнаруживает только изменения последнего коммита; пуши с несколькими коммитами могут пропустить изменённые сервисы | Средние — переключиться на diff github.event.before...after |
Node.js 20 EOL
Dockerfile фронтенда использует node:20-alpine. Node.js 20 достигает конца жизни 2026-06-02. Обновите до node:22-alpine до этой даты. Изменения кода не ожидаются — Vite 5 поддерживает Node 22.
Рекомендуемая следующая фаза¶
Приоритизировано по бизнес-влиянию:
| Фаза | Пункт | Оценка усилий |
|---|---|---|
| 1 | Интеграция биллинга Stripe — принудительные платные тарифы, выставление счетов | 2–3 недели |
| 2 | Email-уведомления (SendGrid/Postmark) — восстановление пароля, алерты по задачам | 1 неделя |
| 3 | Улучшения самообслуживания портала — создание/отзыв API-ключей, запросы на смену тарифа | 1–2 недели |
| 4 | Масштабирование производительности — при достижении порогов нагрузки | 3–4 недели |
Предпосылка для Фазы 1
Интеграция Stripe требует email-провайдера (для подтверждений биллинга и квитанций), поэтому Фазы 1 и 2 лучше разрабатывать совместно.
Сводка архитектуры деплоя¶
Интернет → Cloudflare Proxy (DDoS, WAF)
→ nginx (:443, TLS 1.2+, HSTS)
→ admin-api (FastAPI, только внутренний)
→ postgres / redis (только внутренние)
→ ml-worker (внутренний, BRPOP loop)
→ fal.ai FASHN v1.5 (внешний AI)
Мониторинг: Prometheus → Grafana (внутренний)
Алертинг: AlertManager → Telegram Bot
Бэкапы: pg_dump → /opt/tryon-saas-backups/ (ежедневно, хранение 30 дней)
CI/CD: GitHub Actions → SSH-деплой при успехе CI
Все внутренние сервисы (postgres, redis, prometheus, grafana) не открыты в интернет. В production через UFW открыты только порты 22, 80 и 443.