JWT

Непроверенная инфа: jwt нельзя отзывать, потому что на сервере они не хранятся

JWT: https://research.securitum.com/jwt-json-web-token-security/

Intro

Стандарт JWT крутится вокруг четырех понятий — JWK, JWS, JWE, JWT.

JWK — стандарт, описывающий ключи подписи и шифрования

JWS — стандарт, описывающий как подписывать информацию и хранить всю нужную информацию. Защищает целостность информации при передачи.

JWE — стандарт, описывающий как шифровать информацию и хранить всю нужную информацию. Защищает конфиденциальность информации при передачи.

JWT — стандарт, описывающий как кодировать и декодировать key-value данные в формат для передачи куда-либо.

Как это выглядит в действии

По сути, у нас есть пара значений key и value:

  • JWT: оберни key и value в json и перегони в строку

  • JWK: сгенерируй ключ для подписи и/или шифрования

  • JWE: зашифруй свои данные (payload)

  • JWS: подпиши свои данные (payload)

  • JWT: а еще добавь в заголовок необходимую информацию, чтобы другая сторона смогла расширфовать и/или проверить подпись твоего токена

Время жизни токенов

Access Token — от 5 минут до суток

Refresh Token — до месяца

Attacks

Set alg=none

Пробуем заменить в заголовке параметр alg на none. В этом случае токен подписывать не надо. Если сервер доверяет такому токену -> можем имперсонироваться под любую другую сессию.

Key Injection

Токен может быть подписан с использованием асимметричных алгоримов (например, rsa или ec). В этом случае, проверка токена осуществляется по public key, который может быть указан в заголовке или хранится на сервере в jwks.json параметре (а в заголовке jku ссылка на этот файл).

Мы можем попробовать подписать токен на своем ключе и добавить информацию о публичном ключе в jwk параметр в заголовок токена или указать ссылку на свой сервер, где расположили jwks.json файл.

Вообще, сервер не должен доверять чужим публичным ключам (список публичных ключей должен храниться в белом списке каком-то), но разработчики ошибаются)

Пример: https://portswigger.net/web-security/jwt, смотри про Injecting self-signed JWTs via the jwk parameter.

Inject into kid header

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

Стандарт JWT не регламентирует, что такое kid и каким образом и где он должен хранится. Как результат, в этом месте поверхность атаки может расширится, а именно:

  • Если kid — это файл, то можно попробовать сделать path traversal. Например: ../../../../../../../dev/null и подписываем токен на null-байте на алгоритме HS256, например.

  • Если kid хранится в базе, можно попробовать сделать SQLi.

JWT Algorithm Confusion Attack

Исходные: JWT токен, поддерживает HS и RS алгоритмы подписи.

Находим публичный ключ (например, в /.well-known/jwks.json), кодируем его в нужный формат, переставляем алгоритм подписи в HS и подписываем на этом ключе как на секрете.

С какой-то долей вероятности, на стороне сервера, в качестве секрета (по заголовку) возьмется открытый ключ, а в коде на этапе проверки посмотрят на заголовок alg и проверят на этом секрете — PROFIT.

Lab of PortSwigger: https://portswigger.net/web-security/jwt/algorithm-confusion

Пример: https://hackerone.com/reports/1210502

И даже если мы не знаем публичный ключ(и), имея два JWT с подписью RSA, можем восстановить публичный ключ сервера (CVE-2017-11424). Получить публичные ключи можем с помощью специально подготовленного Docker-контейнера:

docker run --rm -it portswigger/sig2n <token1> <token2>

На выходе получаем base64 закодированные сертификаты в формате X509 и PKCS1 и переподписанные на них как на секретах по алгоритму HS256 токены (если нам не надо ничего менять внутри этих токенов, то можем их сразу отправить для теста).

Другие интересные заголовки, приводящие к атакам

cty

cty (Content Type) - Sometimes used to declare a media type for the content in the JWT payload. This is usually omitted from the header, but the underlying parsing library may support it anyway. If you have found a way to bypass signature verification, you can try injecting a cty header to change the content type to text/xml or application/x-java-serialized-object, which can potentially enable new vectors for XXE and deserialization attacks.

x5c

x5c (X.509 Certificate Chain) - Sometimes used to pass the X.509 public key certificate or certificate chain of the key used to digitally sign the JWT. This header parameter can be used to inject self-signed certificates, similar to the jwk header injection attacks discussed above. Due to the complexity of the X.509 format and its extensions, parsing these certificates can also introduce vulnerabilities. Details of these attacks are beyond the scope of these materials, but for more details, check out CVE-2017-2800 and CVE-2018-2633.

Mitigations

См внизу: https://portswigger.net/web-security/jwt

Some Notes & Tools

Декодер - https://jwt.io/

Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication: https://gist.github.com/zmts/802dc9c3510d79fd40f9dc38a12bccfc

JSON Object Signing and Encryption (JOSE) — проект, в котором перечислены все возможные параметры JWT и операции над ними: https://www.iana.org/assignments/jose/jose.xhtml

Библиотека для работы с JWT, JWS, JWK, ... — jwcrypto. Примеры использования можно найти в тестах к этой библиотеки. Мои примеры работы с этой библиотекой (реализовывал атаки на JWT).

JWT Security Testing https://mazinahmed.net/blog/breaking-jwt

Last updated