SES-018: update /auth/refresh

Техническое задание / Спецификация требований Обновить логику /auth/refresh — Обязательная проверка флага is_revoked

Author

Системный аналитик

Published

May 28, 2026

NoteКраткая карточка задачи
  • Эпик: Авторизация и аутентификация (EPIC-10)
  • Компонент: R Gatekeeper (Backend API), Postgres (Auth DB), Mobile App (AgroLaborApp)
  • Зависимость (Pre-requisite): SES-007 (Реализация логаута и отзыва токена)
  • Статус: Готово к реализации
  • Ссылка на Jira: SES-008

1. Бизнес-контекст и цель (Business Context)

Для защиты пользовательских сессий в платформе “Цифровые симуляторы бизнес-процессов” от перехвата и несанкционированного обновления необходимо внедрить строгую валидацию на этапе ротации ключей. Если злоумышленник скомпрометировал refresh_token, он не должен иметь возможности сгенерировать новые токены, если сессия уже была аннулирована пользователем или системой.

Цель задачи: Обновить логику существующего эндпоинта POST /auth/refresh в микросервисе R Gatekeeper. Сервис должен принудительно проверять состояние флага is_revoked в таблице refresh_tokens базы данных Postgres перед выдачей новой пары access_token и refresh_token.

2. Пользовательские истории (User Stories)

Как Ядро службы безопасности платформы,
Я хочу проверять статус отзыва токена обновления при каждом запросе на ротацию сессии,
Чтобы украденные, утекшие или ранее закрытые через логаут токены не могли использоваться для несанкционированного доступа к системе.


3. Системные требования и бэкенд-логика (Functional Requirements)

3.1. Верификация состояния в базе данных

При поступлении запроса на обновление токенов, сервис R Gatekeeper извлекает хэш токена из защищенной куки и выполняет поиск метаданных в Postgres (Auth DB) по полю token_hash:

SELECT id, user_id, is_revoked, expires_at 
FROM refresh_tokens 
WHERE token_hash = $1;

3.2. Конвейер бизнес-правил валидации (Validation Pipeline)

Бэкенд должен последовательно проверять запись в БД по следующему алгоритму:

[Запрос на обновление сессии]
               │
               ▼
   ┌───────────────────────┐
   │ Токен найден в базе?  ├─► Нет ──► [401 Unauthorized]
   └───────────┬───────────┘
               │ Да
               ▼
   ┌───────────────────────┐
   │ Просрочен expires_at? ├─► Да  ──► [401 Unauthorized] (Сессия истекла)
   └───────────┬───────────┘
               │ Нет
               ▼
   ┌───────────────────────┐
   │    is_revoked == true?├─► Да  ──► [403 Forbidden] (ФИКСАЦИЯ REPLAY ATTACK!)
   └───────────┬───────────┘
               │ Нет (Токен валиден)
               ▼
 [Генерация новой пары токенов]
  1. Правило 1 (Существование): Если запись с указанным token_hash отсутствует в БД, возвращать ошибку 401 Unauthorized.
  2. Правило 2 (Срок действия): Если текущее системное время NOW() > expires_at, возвращать ошибку 401 Unauthorized с сообщением об истечении сессии.
  3. Правило 3 (Отзыв токена - Основная задача): Если поле is_revoked == true, немедленно прервать транзакцию. Запрещено генерировать новые ключи. Запрос классифицируется как попытка повторного использования (Replay Attack). Возвращать статус 403 Forbidden со специальным телом ответа.

4. Спецификация API (API Specification Updates)

POST /auth/refresh

Используется для ротации сессии и выдачи нового Access Token.

Пример запроса (Headers):

POST /auth/refresh HTTP/1.1
Host: ://yourcompany.com
Cookie: refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Сценарий А: Успешное обновление (Response 200 OK) Если is_revoked == false и срок действия не истек, бэкенд производит ротацию (старый токен помечается как отозванный, создается новая запись) и возвращает новый ключ доступа:

{
  "success": true,
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "message": "Tokens successfully rotated."
}

Сценарий Б: Токен ранее был отозван / Попытка взлома (Response 403 Forbidden) Если при поиске в БД обнаружено, что is_revoked == true:

{
  "success": false,
  "error": {
    "code": "TOKEN_REVOKED_REPLAY_ATTACK",
    "message": "The provided refresh token has been revoked. Security alert raised.",
    "details": {
      "reason": "Session was previously terminated or flagged as compromised",
      "action_required": "FORCE_LOCAL_LOGOUT"
    }
  },
  "timestamp": "2026-05-28T06:55:00Z"
}

5. Критерии приемки и тест-кейсы для QA

Тест-кейс 1: Стандартное обновление активной сессии

  • Дано: Авторизованный клиент. В БД Postgres запись токена имеет is_revoked = false и expires_at в будущем.
  • Когда: Отправляется запрос POST /auth/refresh.
  • Тогда: Ответ содержит статус 200 OK, выдается новый accessToken, сессия продолжается штатно.

Тест-кейс 2: Попытка атаки с использованием отозванного токена (Анализ безопасности)

  • Дано: Запись токена в БД имеет статус is_revoked = true после успешного логаута в задаче SES-007.
  • Когда: Злоумышленник (или устаревший кэш мобильного приложения) отправляет запрос POST /auth/refresh с этим хэшем.
  • Тогда:
    • API возвращает строго 403 Forbidden.
    • Тело ответа полностью соответствует структуре ошибки TOKEN_REVOKED_REPLAY_ATTACK.
    • Мобильное приложение AgroLaborApp перехватывает этот код и запускает процедуру жесткого логаута (очистка памяти и редирект на экран логина).