Привет,
Что ж, это моя первая запись, и по мере ее написания может быть множество ошибок, поэтому, пожалуйста, дайте мне отзыв, чтобы я мог над этим поработать.
Итак, начнем!
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
Эти три части:
- Заголовок
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