## MOC: Паттерны безопасности PhotoPlaces ### Аутентификация и сессии ```mermaid 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