MOC-security-patterns.md 5.0 KB

MOC: Паттерны безопасности PhotoPlaces

Аутентификация и сессии

graph LR
    A[Login] --> B[Access Token JWT 15min]
    A --> C[Refresh Token SHA-256 в DB]
    C --> D[HttpOnly Cookie SameSite=Strict]
    B --> E[Bearer Authorization Header]
    D --> F[/auth/refresh → rotation]
    F --> G[Token reuse → RevokeAll]

Ключевые решения

Область Решение Документ
Refresh token storage SHA-256 хеш в PostgreSQL + ротация [[backend-auth-security]]
Concurrent refresh DeleteIfExists + проверка rows_affected [[atomic-refresh-token-race-condition]]
CSRF SameSite=Strict для refresh cookie [[atomic-csrf-protection]]
Rate limiting Redis + in-memory fallback, per-IP / per-UserID [[backend-rate-limiting]]
Fail-open vs Fail-closed Зависит от AppEnv [[atomic-redis-rate-limiter-failopen-failclosed]]
WebSocket per-connection rate limiter, глобальный лимит 1000 [[atomic-websocket-origin-check]]
Error exposure Скрытие деталей в production (500 + validation) [[decision-validation-error-production]]
CSP Content-Security-Policy через Caddy [[atomic-csp-hardening]]
TOCTOU race (anti-pattern) Race при регистрации [[atomic-toctou-race-registration]]
Package-level state (anti-pattern) var AppEnv глобальная [[atomic-global-appenv-package-var]]

Production hardening

  • CORS: только разрешённые AllowedOrigins, валидация при старте (config.go:106)
  • CSP: Content-Security-Policy через Caddy, но с unsafe-inline — нужно hardening ([[atomic-csp-hardening]])
  • JWT secrets: _FILE suffix для Docker secrets, panic если в production = dev-secret
  • Request body: http.MaxBytesReader (1 MB лимит) на всех JSON-инпутах
  • Rate limiter: fail closed в production (503 при недоступности Redis)
  • WebSocket: проверка Origin, глобальный лимит 1000 соединений
  • DB: параметризованные запросы (pgx), soft delete через deleted_at
  • File upload: whitelist content-type (jpeg, png, webp, heic) + проверка magic-bytes ([[atomic-file-upload-magic-bytes]]), серверная генерация имени (uuid), лимит размера

Антипаттерны (требуют исправления)

Проблема Файл Риск
var AppEnv string — глобальная mutable-переменная handlers/errors.go:13 Нет тестов, race при параллельных запросах
TOCTOU race в Register services/auth.go:85-86 Дубликат email при одновременной регистрации
Ошибка GetByEmail подавлена через _ services/auth.go:85 При недоступности БД — "email exists" вместо 500
CSP с unsafe-inline + unsafe-eval Caddyfile:40 XSS-защита ослаблена

Проверки аудита

  1. Все ли секреты вынесены из кода? (✓ env vars / Docker secrets, но ещё есть dev-secret в .env.example)
  2. Используются ли параметризованные запросы? (✓ pgx)
  3. Есть ли any/interface{} в публичных API? (✓ в writeJSON(v interface{}) — допустимо, транспорт)
  4. Есть ли race условия? (⚠ var AppEnv, TOCTOU в Register)
  5. Тестируется ли security? (— нет, нужно добавлять)
  6. Скрыты ли детали ошибок в production? (✓ для 500 и validation)
  7. Есть ли rate limiting на sensitive endpoints? (✓ auth: 10/min, write: 10/min)

Связанные заметки

  • [[architecture-overview]] — таблица P0-P2
  • [[backend-auth-security]] — JWT и refresh token
  • [[backend-rate-limiting]] — rate limiting
  • [[backend-validation]] — валидация
  • [[deploy-production-readiness]] — production readiness
  • [[atomic-global-appenv-package-var]] — глобальная переменная
  • [[atomic-toctou-race-registration]] — TOCTOU race
  • [[atomic-error-swallowing-frontend]] — подавление ошибок
  • [[atomic-csp-hardening]] — CSP hardening
  • [[atomic-redis-rate-limiter-failopen-failclosed]] — fail-open/closed
  • [[atomic-file-upload-magic-bytes]] — проверка сигнатуры загружаемых файлов
  • [[atomic-sentinel-error-handler-mapping]] — маппинг sentinel-ошибок в HTTP-статусы
  • [[atomic-booking-status-transition-guard]] — условные переходы статуса
  • [[atomic-fetch-retry-infinite-loop]] — guard от рекурсии при refresh

#security #MOC #backend #auth #production #anti-pattern