JWT 编程语言之间的差异
Posted
技术标签:
【中文标题】JWT 编程语言之间的差异【英文标题】:JWT differences between Programming Languages 【发布时间】:2019-01-20 18:29:55 【问题描述】:我有一个用 Python 编写的 API 和另一个用 Ruby 编写的 API。我们需要它们在它们之间发送数据,并决定使用 JWT 作为身份验证方法。基本上在两端生成一个令牌并确保它们匹配。现在我遇到了 python 和 ruby 之间匹配哈希的问题。鉴于此代码:python (2.7) PyJWT == 1.6.4
>>> import jwt
>>> jwt.encode("someKey":123, "secret", algorithm='HS256')
u'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lS2V5IjoxMjN9.DL8qyWMeqfMMLCTPN3RA9K08e-AkNW_ybPyywvrIIZ8'
这似乎在 python 版本之间也发生了变化——运行这个作为 python3 产生了这个
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhcHBlbklkIjoxMjN9.YgFKZePJYMRDMgubCeZBy6WaFKiTA9C-TRnnZLFJC8E'
然后,当我在 ruby 中创建一个类似的“函数”时,我得到一个不同的哈希值 - 这在 ruby 的 jwt 版本之间也是如此(我已经测试过 jwt-1.5.6 和 jwt-2.1.0) - 下面是jwt-1.5.6 结果。
require "jwt"
someKey = 123
secret = "secret"
payload = "someKey" => someKey
token = JWT.encode payload, secret, 'HS256'
puts token
该代码的输出是
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb21lS2V5IjoxMjN9.7Ch3o7IXmxqm79AcrTetXuZv6h3suyLD5_IgXdrRlNs
使用 jwt-2.1.0 版本,我得到:
eyJhbGciOiJIUzI1NiJ9.eyJzb21lS2V5IjoxMjN9.QkKm2IuvOz_D5ukIxOsjMYApzV2ZnjLE2HII3ZfP_hsWith
为什么这两个代码集的输出会产生两个不同的哈希值?
编辑: 当我使用 jwt.io 时
https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lS2V5IjoxMjN9.DL8qyWMeqfMMLCTPN3RA9K08e-AkNW_ybPyywvrIIZ8
我得到与 python 相同的令牌
【问题讨论】:
jwt 1.5.6 和 jwt 2.1.0 是否使用相同的哈希函数?您是否在散列相同的数据(python 中的字典不是 JSON)?有趣的问题,但从设计的角度来看,你可能不应该这样做:) 您只能在 python 端使用 dict(jwt.encode 只接受 dicts) - 但对于 Ruby 端,该函数接受 dict 或 JSON 字符串 - 两者都不匹配。 没怎么看代码,但是Python3中默认切换为Unicode字符串,Python2中不是这样。这会导致不同的输出吗?使用 Python2 将u
添加到字符串中,然后查看输出是否匹配。
如果您检查 JWT.io 上的所有 JWT,您会看到不同的标头字段顺序(但值相同),只有第二个 ruby 示例缺少 typ
标头。有效载荷是"someKey":"123"
,但在python3中它改为"appenId":"123"
。难怪结果不一样。 JWT 的想法不是生成相同的令牌来比较它们,而是拥有一个签名,使您能够验证令牌本身。
【参考方案1】:
所以我解决了这个问题,正如@jps 提到的,Ruby 代码没有标头 "typ":"JWT" - python 代码有。如 ruby jwt 的文档中所述,您可以设置标题。这是在 ruby 端修复它的代码。
token = JWT.encode(payload=payload, key=key, algorithm='HS256',header_fields= typ: 'JWT' )
现在令牌匹配了。顺便说一句,即使不同的哈希值也可以通过相同的秘密进行解码 - 身份验证中只有一个额外的步骤来仔细检查创建的哈希值是否与传入的哈希值匹配。
【讨论】:
【参考方案2】:无需在双方都创建令牌。
将 JWT 策略与 RS256
之类的 pub priv 密钥算法一起使用。有了这个,您可以在一个 API 中签署 JWT 令牌,并能够使用您的另一个 API 中的公钥进行验证。
【讨论】:
我完全同意你的看法。 auth 方法不是我设计的,更改它会破坏很多部分。以上是关于JWT 编程语言之间的差异的主要内容,如果未能解决你的问题,请参考以下文章