Как мне отредактировать заголовок JWT в python 3.7? - PullRequest
0 голосов
/ 09 января 2019

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

Проблема в том, что всякий раз, когда я генерирую токен с использованием PyJWT, заголовок (после декодирования base64): {"typ":"JWT","alg":"HS512"} но большинство токенов JWT, которые я пытаюсь взломать, имеют следующий заголовок: {"alg":"HS512","typ":"JWT"}

token = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS512'}

Это токен, который я получаю:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzb21lIjoicGF5bG9hZCJ9.EgMnzcJYrElON09Bw_OwaqR_Z7Cq30n7cgTZGJqtK1YHfG1cGnGJoJGwOLj6AWg9taOyJN3Dnqd9NXeTCjTCwA

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

Буду признателен за любую помощь, желательно, я бы хотел остаться с python и не переходить на другой язык программирования.

1 Ответ

0 голосов
/ 13 января 2019

Если вы собираетесь использовать грубую силу JWT (что будет огромным предприятием, удачи вам в этом), то просто сгенерируйте подпись самостоятельно, непосредственно из первых двух частей. Словари Python и объекты JSON являются неупорядоченными структурами , поэтому любой порядок действителен, спецификации JWT не определяют порядок, и любая реализация JWT просто берет существующие данные для первых двух частей для проверки подписи. Они не будут повторно генерировать JSON.

Библиотека PyJWT предоставляет все поддерживаемые алгоритмы в виде отдельных объектов в модуле jwt.algorithms; просто позвоните jwt.algorithms.get_default_algorithms(), чтобы получить имя сопоставления словаря для Algorithm экземпляр .

Каждый такой объект имеет методы .sign(msg, key) и .verify(msg, key, sig). Передайте первые два сегмента (в кодировке base64, с ., в качестве объекта bytes) в качестве сообщения, и вы получите двоичную сигнатуру ( not base64 кодированный) обратно при использовании .sign() или при проверке с помощью .verify() вы передаете двоичную подпись, декодированную из данных base64.

Таким образом, для данного token как bytes объекта вы можете получить алгоритм и проверить ключ с помощью:

import json
from jwt.utils import base64url_decode
from jwt.algorithms import get_default_algorithms

algorithms = get_default_algorithms()

msg, _, signature_part = token.rpartition(b'.')
header = json.loads(base64url_decode(msg.partition(b'.')[0]))
algo = algorithms[header['alg']]
signature = base64url_decode(signature_part)

# bytes key from other source; brute-force or otherwise
if algo.verify(msg, key, signature):
    # key correct

Учитывая, что для вашего образца token и key установлено значение b'secret', вышеуказанное подтверждает:

>>> import json
>>> from jwt.utils import base64url_decode
>>> from jwt.algorithms import get_default_algorithms
>>> token = b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzb21lIjoicGF5bG9hZCJ9.EgMnzcJYrElON09Bw_OwaqR_Z7Cq30n7cgTZGJqtK1YHfG1cGnGJoJGwOLj6AWg9taOyJN3Dnqd9NXeTCjTCwA'
>>> key = b'secret'
>>> algorithms = get_default_algorithms()
>>> msg, _, signature_part = token.rpartition(b'.')
>>> header = json.loads(base64url_decode(msg.partition(b'.')[0]))
>>> algo = algorithms[header['alg']]
>>> signature = base64url_decode(signature_part)
>>> algo.verify(msg, key, signature)
True

Грубое принуждение путем генерации ключа в цикле становится тривиальным для проверки. Обратите внимание, что что-либо, кроме маленькой клавиши (с использованием ограниченного алфавита), очень быстро будет невозможно; 16-байтовое полностью случайное значение ключа (128 бит) потребует от вас нескольких десятилетий для того, чтобы полностью перестроиться на современном оборудовании даже с языком системного программирования, не говоря уже о более медленной скорости цикла Python.

...