Как мне отредактировать заголовок JWT в python 3.7?
Я пытаюсь написать программу, которая будет пытаться взломать секрет, используемый для подписи подписи в токене 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 ответ
Если вы собираетесь использовать грубую силу JWT (что будет огромным предприятием, удачи вам в этом), то просто сгенерируйте подпись самостоятельно, непосредственно из первых двух частей. Словари Python и объекты JSON являются неупорядоченными структурами, поэтому любой порядок действителен, спецификации JWT не определяют порядок, и любая реализация JWT просто берет существующие данные для первых двух частей для проверки подписи. Они не будут повторно генерировать JSON.
Библиотека PyJWT предоставляет все поддерживаемые алгоритмы в виде отдельных объектов в jwt.algorithms
модуль; просто позвони jwt.algorithms.get_default_algorithms()
чтобы получить имя сопоставления словаря Algorithm
экземпляр.
Каждый такой объект имеет .sign(msg, key)
а также .verify(msg, key, sig)
методы. Передайте в первых двух сегментах (в кодировке base64, с .
, как bytes
объект), и вы получите бинарную подпись (не в кодировке 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.