如何在 python 3.7 中编辑 JWT 标头?

Posted

技术标签:

【中文标题】如何在 python 3.7 中编辑 JWT 标头?【英文标题】:How do I edit the JWT header in python 3.7? 【发布时间】:2019-06-04 04:18:24 【问题描述】:

我正在尝试编写一个程序,该程序将尝试通过单词列表暴力破解用于在 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”和“算法”。

任何帮助将不胜感激,最好是我想继续使用 python 而不是更改为其他编程语言。

【问题讨论】:

如果您要暴力破解 JWT(这将是一项艰巨的任务,祝您好运),然后直接从前两部分自己生成签名。 Python 字典和 JSON 对象是无序结构,任何 JWT 实现只需要前两部分的现有数据来验证签名。他们不会重新生成 JSON。 这并不是为了实际使用正确的 jwt,它是为一个简单的秘密单词的练习而制作的。 【参考方案1】:

如果您要暴力破解 JWT(这将是一项艰巨的任务,祝您好运),那么您只需自己直接从前两部分生成签名。 Python 字典和 JSON 对象是无序结构,因此任何一种顺序都是有效的,JWT 规范没有指定顺序,任何 JWT 实现只需要前两部分的现有数据来验证签名。他们不会重新生成 JSON。

PyJWT 库在jwt.algorithms 模块中将所有支持的算法作为单独的对象提供;只需调用jwt.algorithms.get_default_algorithms() 以获取到Algorithm instance 的字典映射名称。

每个这样的对象都有.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

假设您的样本 tokenkey 设置为 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 循环的较慢速度了。

【讨论】:

你的方法就像一个魅力,我想我没有像我一开始应该那样接近它。

以上是关于如何在 python 3.7 中编辑 JWT 标头?的主要内容,如果未能解决你的问题,请参考以下文章

如何正确处理标头中的 JWT

如何在 api 请求标头中插入 api 身份验证所需的 jwt 令牌?

如何验证请求标头、JWT 令牌

如何在 Angular 中从服务器获取带有 jwt 令牌的响应标头

使用 Rails 和 React 时如何在标头中获取 JWT 令牌

如何在 Slim 3 响应标头中附加 JWT 令牌