Что делать при компрометации секретного ключа JWT
Что проверяют
Понимаете ли вы, что подписанный токен нельзя отозвать поштучно, и знаете ли, из чего складывается реагирование: смена ключа, обесценивание всего выданного, закрытие канала утечки. Заодно смотрят, как в вашем приложении хранятся и перечитываются секреты.
Как отвечать
План по шагам. Немедленно выпустить новый ключ и переключить на него выдачу. Старый полностью убрать из проверки: пока он принимается, злоумышленник подписывает им токены с любыми ролями. Параллельно обесценить выданное: отозвать refresh-токены в хранилище, поднять версию учётной записи (в готовой инфраструктуре эту роль играет SecurityStamp), чтобы старые access-токены отбрасывались до истечения срока.
В ASP.NET Core это настройка TokenValidationParameters: набор IssuerSigningKeys, явный список допустимых алгоритмов, включённые ValidateIssuer, ValidateAudience, ValidateIssuerSigningKey. Разумный шаг после инцидента это переход на асимметричную подпись, где приватный ключ есть только у сервиса выдачи, остальные проверяют публичным из набора JWKS, а kid в заголовке токена позволяет ротировать ключи без простоя.
Скажите и про причину, а не только про симптом: секрет в репозитории или в конфиге образа, долгоживущий access-токен, один ключ на все окружения. После разбора ключ уезжает в менеджер секретов, срок жизни access-токена сокращается до минут, ротация становится плановой, появляется аудит выдач и отзывов.
Где спотыкаются
Оставляют старый ключ в списке проверки ради плавной миграции. Это ровно то, что нужно атакующему: новый ключ никак не мешает подделывать токены старым. Плавность даёт короткий срок жизни токена, а не двойная валидация.
Второе: считают, что смена ключа выкидывает всех. Refresh-токены обычно лежат в базе и с подписью не связаны, так что без их отзыва сессии восстановятся, и человек с украденным токеном спокойно продолжит работу.
Третье: путают подпись и шифрование. Обычный JWT подписан, но не зашифрован: полезная нагрузка читается кем угодно, поэтому персональные данные и внутренние признаки в claims класть нельзя, и сменой алгоритма это не лечится.