Можно ли посмотреть содержимое перехваченного JWT токена
Что проверяют
Понимаете ли вы, что JWT это подписанный, а не зашифрованный токен. От этого зависит, положите ли вы в полезную нагрузку то, чего там быть не должно, и как будете проверять токен на стороне сервиса.
Как отвечать
Да, содержимое видно любому, кто получил токен. Стандартный подписанный токен состоит из трёх частей через точку: заголовок, полезная нагрузка и подпись. Первые две это обычный base64url без всякого шифрования, раскодировать их можно чем угодно, ключ для этого не нужен.
import jwt
claims = jwt.decode(token, options={"verify_signature": False})Дальше важно развести два свойства. Подпись даёт целостность и подлинность: изменить sub или role в полезной нагрузке можно, но подпись перестанет сходиться, и сервер такой токен отклонит. Конфиденциальности подпись не даёт вовсе, поэтому персональные данные, внутренние идентификаторы и тем более секреты в claims не кладут. Нужна скрытая нагрузка, это уже JWE, отдельный формат.
Отсюда практические выводы: токен ходит только по HTTPS, живёт коротко, обновляется по refresh-токену, а на сервере проверяется не только подпись, но и exp, iss, aud и список разрешённых алгоритмов.
Где спотыкаются
Говорят «токен зашифрован». Это самая дорогая ошибка: за ней обычно следует телефон или внутренний флаг доступа в полезной нагрузке, который видно прямо из браузера.
Второе: проверяют подпись, но не ограничивают алгоритм. Если брать alg из заголовка самого токена, атакующий подставит none либо подменит RS256 на HS256 и подпишет токен публичным ключом. В jwt.decode алгоритмы задаются явно списком, и это не формальность.
Третье: путают декодирование с валидацией. Вызов с выключенной проверкой подписи удобен для отладки, но в боевом коде он означает, что авторизации у сервиса фактически нет: подойдёт любой токен нужной формы.