После выдачи нового refresh-токена клиент повторно предъявил старый. Как ротация refresh-токенов позволяет обнаружить компрометацию?
При ротации refresh-токенов каждый успешно использованный токен немедленно заменяется новым, а старый помечается как использованный. Повторное предъявление старого токена означает возможное копирование и воспроизведение токена; сервер должен отозвать всю связанную цепочку токенов или сессию, чтобы украденный токен больше не давал возможности получать новые access-токены.
Долгоживущие bearer-токены создают проблему: любой, кто получил токен, может предъявить его без доказательства владения устройством или секретом. Простого контроля срока действия недостаточно, поскольку украденный токен остаётся пригодным до истечения этого срока.
Ротация появилась как способ сократить окно незаметного использования украденного refresh-токена. Она превращает повторное использование уже погашенного токена в наблюдаемое событие безопасности.
Без ротации один refresh-токен может многократно использоваться для выпуска новых access-токенов. Если злоумышленник скопировал его, сервер обычно не отличит повторное использование злоумышленником от обычного запроса легитимного клиента.
При ротации возникает состояние гонки: легитимный клиент использует токен, получает замену, а злоумышленник позже предъявляет копию старого токена. Если сервер просто отклонит второй запрос без дополнительных действий, украденный токен может оставаться действительным в другой параллельной цепочке или злоумышленник сможет использовать уже полученную замену.
Сервер хранит для каждого refresh-токена или его защищённого идентификатора состояние: срок действия, принадлежность клиенту и сессии, признак использования и связь с семейством токенов. При успешном обмене старый токен атомарно помечается использованным, а клиенту выдаётся новый токен, связанный с тем же семейством.
Если старый токен предъявляют повторно, сервер фиксирует replay. Типичная реакция — немедленно отозвать всё семейство токенов, включая последний выданный токен, и потребовать повторную аутентификацию. Иначе злоумышленник, успевший получить новый токен, всё ещё сможет продолжать сессию.
Операция замены должна быть атомарной: два параллельных запроса не должны оба успешно использовать один и тот же refresh-токен. Проверка принадлежности клиенту, срока действия, отзыва и криптографической целостности токена также выполняется до выдачи новой пары токенов.
Ротация не доказывает, кто именно является злоумышленником. Она обнаруживает факт, несовместимый с корректным последовательным использованием токена. Поэтому возможны ложные срабатывания из-за повторной доставки запроса, сбоя сети, восстановления клиента из резервной копии или неправильной параллельной работы нескольких экземпляров приложения.
Для снижения ущерба обычно сочетают ротацию с коротким временем жизни access-токенов, защищённым хранением refresh-токенов, ограничением аудитории и области действия, журналированием и уведомлением о подозрительном отзыве. Если архитектура позволяет, sender-constrained-токены дополнительно связывают токен с ключом клиента и уменьшают ценность украденной копии.
Мобильное приложение отправило запрос на обновление с refresh-токеном, но из-за сетевого сбоя не получило ответ. Пользователь повторил запрос, а сервер уже успел выдать новый токен и пометить старый использованным. Наивная реализация расценила повтор как компрометацию и отозвала сессию.
Рассматривались три варианта. Полный отзыв семейства хорошо ограничивает злоумышленника, но ухудшает пользовательский опыт при обычных сбоях. Разрешение повторного использования старого токена в течение небольшого окна уменьшает ложные срабатывания, но оставляет окно для атаки. Хранение результата предыдущей операции позволяет безопасно вернуть тот же ответ при повторе, но требует аккуратной идемпотентности и дополнительного состояния.
Было выбрано атомарное хранение результата обмена с ограниченным сроком его повторной выдачи, после которого повторное использование трактуется как replay и приводит к отзыву семейства. Это сохраняет устойчивость к повторной доставке запроса, но не маскирует длительное или позднее использование украденного токена.
Если отозван только старый токен, злоумышленник может успеть использовать новый токен, который был выдан легитимному клиенту до обнаружения replay. Отзыв всего семейства связывает обнаруженное событие с последующими заменами и закрывает эту цепочку.
Нужно различать повтор того же самого запроса и независимое повторное предъявление токена. Для этого сервер может атомарно сохранить результат обмена, идентификатор операции и ограниченное время, в течение которого повтор возвращает уже подготовленный результат. Такой механизм не должен позволять произвольному повторному использованию токена и обязан учитывать параллельные запросы.
При sender constraint сервер принимает токен только вместе с доказательством владения соответствующим ключом. Копия одного лишь токена становится недостаточной для атаки, поэтому риск replay уменьшается. Однако компрометация самого ключа, ошибки в его хранении и отсутствие корректной проверки доказательства всё равно могут привести к захвату сессии; ротация остаётся полезным механизмом обнаружения повторного использования.