backend-auth-security.md 3.3 KB

Backend: Безопасность JWT и Refresh Tokens

Контекст: В backend/internal/services/auth.go реализована JWT-аутентификация с access (15 мин) и refresh (30 дней) токенами. Текущая реализация имеет критические уязвимости.

Суть

Refresh токены не сохраняются в БД — они валидируются только по криптографической подписи. Это значит:

  1. Нет возможности отозвать токен (logout, смена пароля, бан пользователя)
  2. Нет ротации refresh токенов (уязвимость к replay атакам)
  3. Утечка refresh токена = полный доступ на 30 дней
  4. Нельзя ограничить количество активных сессий пользователя

Код (проблемное место)

// backend/internal/services/auth.go:152-164
func (s *AuthService) ValidateRefreshToken(tokenString string) (string, error) {
    token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(t *jwt.Token) (interface{}, error) {
        return s.refreshSecret, nil  // Только проверка подписи!
    })
    // ... нет проверки в БД, нет отзыва
}

Решение (Best Practice)

Хранить хеш refresh токена в таблице refresh_tokens (уже есть в миграции 000002_create_users.up.sql):

CREATE TABLE refresh_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id),
    token_hash VARCHAR(255) NOT NULL,  -- SHA-256 от токена
    expires_at TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

Алгоритм:

  1. При логине: генерируем refresh token → сохраняем SHA256(token) в БД → отдаём пользователю plain token
  2. При refresh: хешируем полученный токен → ищем в БД → проверяем expires_atудаляем старый, создаём новый (ротация)
  3. При logout / смене пароля / бане: удаляем все токены пользователя из БД

Альтернативы

Подход Плюсы Минусы
БД + ротация (рекомендую) Полный контроль, отзыв, безопасность Немного сложнее, лишний round-trip к БД
JWT blacklist в Redis Быстро, не трогает БД Нужно хранить до expiry, нет ротации
Короткий access + долгий refresh без БД Просто Небезопасно — текущее состояние

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

  • [[decision-jwt-refresh-storage]]
  • [[backend-rate-limiting]]
  • [[architecture-overview]]

Источник

Задача: Code review PhotoPlaces — выявление критических уязвимостей безопасности

Теги

#backend #security #jwt #auth #critical #best-practice