验证 JWT 令牌签名而不在 PyJWT 库中对其进行解码

问题描述

是否可以在不使用 PyJWT 库中解码的情况下验证 JWT 令牌签名?

解决方法

我不知道我是否得到了您的要求,但无论如何我都会尝试。

整个 JWT 标准在此 link 中有很好的解释。 本质上,如果我理解您的要求,您希望在不解码令牌本身的情况下检查签名。 为了回答您的问题,我将使用链接中的一些内容。

在其紧凑形式中,JSON Web Token 由以点 (.) 分隔的三个部分组成,它们是:

  • Header:通常由两部分组成,令牌的类型,即 JWT,以及所使用的签名算法,例如 HMAC SHA256 或 RSA(您使用的是 RSA)。

  • Payload:包含声明。声明是关于一个实体的声明(这是你正在解码以找到我假设的公钥的链接)

  • 签名:要创建签名部分,您必须获取编码的标头、编码的有效载荷、秘密、标头中指定的算法,并对其进行签名。例如,如果你想使用 HMAC SHA256 算法,签名将通过以下方式创建:

    HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(有效载荷), 秘密)

签名用于验证消息在整个过程中没有改变,并且,在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者是它所说的人是。

这三个元素是base64编码的,并用“.”连接。因此 JWT 是这样的:akuhsdk.wqkhkwje.sajgdhwqj

所以,如果我想签署一条消息以证明它来自我,我可以用我自己的私钥生成一个签名。任何有兴趣验证消息的人都可以使用我的公钥来确认签名是否有效。

此时,接收者可以通过解密签名并检查它是否有效来验证签名(大多数加密库会抛出错误)。如果不是,那么用于加密它的私钥就不是密钥对中的那个。

示例

import jwt

token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoxMjN9.HT1kBSdGFAznrhbs2hB6xjVDilMUmKA-_36n1pLLtFTKHoO1qmRkUcy9bJJwGuyfJ_dbzBMyBwpXMj-EXnKQQmKlXsiItxzLVIfC5qE97V6l6S0LzT9bzixvgolwi-qB9STp0bR_7suiXaON-EzBWFh0PzZi7l5Tg8iS_0_iSCQQlX5MSJW_-bHESTf3dfj5GGbsRBRsi1TRBzvxMUB6GhNsy6rdUhwoTkihk7pljISTYs6BtNoGRW9gVUzfA2es3zwBaynyyMeSocYet6WJri97p0eRnVGtHSWwAmnzZ-CX5-scO9uYmb1fT1EkhhjGhnMejee-kQkMktCTNlPsaUAJyayzdgEvQeo5M9ZrfjEnDjF7ntI03dck1t9Bgy-tV1LKH0FWNLq3dCJJrYdQx--A-I7zW1th0C4wNcDe_d_GaYopbtU-HPRG3Z1SPKFuX1m0uYhk9aySvkec66NBfvV2xEgo8lRZyNxntXkMdeJCEiLF1UhQvvSvmWaWC-0uRulYACn4H-tZiaK7zvpcPkrsfJ7iR_O1bxMPziKpsM4b7c7tmsEcOUZY-IHEI9ibd54_A1O72i08sCWKT5CXyG70MAPqyR0MFlcV7IuDtBW3LCqyvfsDVk4eIj8VcSU1OKQJ1Gl-CTOHEyN-ncV3NslVLaT9Q1C4E7uK2QpS8z0'
public_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCcjWidoIPNRc3IN1hoGeOdSvDkBDK3W3P7/4HxLf62nvUQVczL3FG+dG9KSRnzuvRoUi1o3TASO3Yn72FSfaLPE/JmOtpu/IGuB/oF/CrJqEHA/08n0xkNQK8kwdIqayKPS84PVOm8XomNijMpUCahqu9cGZDPhlgqD8PAxw4e1ZQSizWj0hTSCR78dmHAEr5oXryP6uD0Mw/KGKYel/KTMu00dShWPzHnJeLaYvKgMJKPN6pqhsWFQsNUDnKd9tgn3NSPeHECnnBbUxB2BeuVz72+HnyFWah3mpGH4Dr+9rjRXiPg2AYxgR3U93AEQ6osefxeIKUSCXWx1txNV07QzwFVag4vPBmrA9XktC7i5EP91wxUOsyzhG8geXKuDHmE+/7U3AsExHYFkBLqMnW92CaTeQ408xsRXjxWjSNHpfqhZVxGY5Eh8L3NVqgRg1LdnZYHpovi1iP4Zx2Z7Nb5F9ejuMsA+v/D0WL3c6bhwU8BKdD7YZDG2tpzq6PHt+NarGkcWWh9/p/SIJoZi+e35mjcUMfnRD8w/ouL0sTnxebT7xBCVucfRoMPA67USoChDpc+pNsdtsqlQOZMgpPZYfjIyCThv5mwjEKHnytBq46ULOFlHt0opplDANnDsvWwqEobhACZM+n2ZNtu36eoc3bC/Hak8ACEi5DixirF0w== miguel@MS90J8G8WL'

payload = jwt.decode(token,public_key,algorithms=['RS256'])

print(payload)

所以,是的,你可以做到。

但是要完成您对代码的要求,您必须使用其他一些库(加密),因为 pyJWT 仅提供 decode 方法,该方法需要一个完整令牌(标头+有效负载+签名),如示例中所示。此外,您必须存储在第一次读取令牌期间获得的标头以获取使用的加密算法(如果更改)。

但是,您为什么不想再次解码它?通过这种方式,您甚至可以检查它是否与已签名的消息相同,并且没有人篡改消息。