如果使用 python 计算,JWT hs512 签名与 jwt.io 略有不同

JWT hs512 signature slightly different from jwt.io if calculated with python

所以我得到了同一个 JWT 的不同签名。

页眉:

{
  "alg": "HS512",
  "typ": "JWT"
}

有效负载:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

作为签名密钥,我使用了“abc

jwt.io 生成的 JWT 如下:eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.sNgS2IRq0LCvUaIzg9dCBVvmY_9KnrXDEmKTii6U4APbRMeUkU084wf3h5v4baP2WeZOyGunCTEa9wxh25IW6w

如果我像这样使用 python 计算签名:

import hmac
import hashlib
import base64

s= b"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"

res = base64.b64encode(hmac.new(b"abc", msg=s, digestmod=hashlib.sha512).digest())

print(res)

然后打印出来: b'sNgS2IRq0LCvUaIzg9dCBVvmY/9KnrXDEmKTii6U4APbRMeUkU084wf3h5v4baP2WeZOyGunCTEa9wxh25IW6w=='

现在除了最后两个字符“==”和这个“/”外,它们完全相同。有人可以向我解释为什么会这样吗?它只是base64的填充,实际上两个等号是否存在并不重要?这就是 jwt.io 删除它们的原因吗?

编辑: 根据 jps 的提示更改 python 代码就可以了:

import hmac
import hashlib
import base64

s= b"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"

res = base64.b64encode(hmac.new(b"abc", msg=s, digestmod=hashlib.sha512).digest())
x = res.decode("utf-8")
x = x.replace("+","-")
x = x.replace("/","_")
x = x.replace("=", "")
print(x)

在您的 Python 代码中您使用了 Base64 编码,但是 JWT standard requires Base64URL 编码。不同之处在于将Base64编码中的字符“+”和“/”替换为“-”和“_”,并省略了填充。

它可能有效也可能无效,具体取决于接收方 Base64URL 解码器的实现。为了安全起见,我建议按照标准来做。