jwt - 如何使用在线工具手动验证 JWT 签名
问题描述
据我所知,验证JWT
签名是一个简单的过程。但是当我使用一些在线工具为我做这件事时,它不匹配。如何在JWT
不使用 JWT 库的情况下手动验证签名?我需要一种快速方法(使用可用的在线工具)来演示这是如何完成的。
我使用以下信息JWT
在https://jwt.io/#debugger-io上创建了我的:
- 算法:
HS256
- 秘密:
hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6
- 标题:
{ “alg”:“HS256”, “典型”:“智威汤逊” }
- 有效载荷:
{ “子”:“1234567890”, “名称”:“约翰·多伊”, “iat”:1516239022 }
- 验证签名(部分):
- 秘密值更改为以上
- “检查”秘密 base64 编码(无论是否检查,仍然得到不同的值)
智威汤逊:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wDQ2mU5n89f2HsHm1dluHGNebbXeNr748yJ9kUNDA
手动JWT
签名验证尝试:
使用base64UrlEncode 计算器(http://www.simplycalc.com/base64url-encode.php或https://www.base64encode.org/)
如果我:( 不是网站上的实际价值,已修改以显示工具最终将为我构建的内容)
base64UrlEncode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9") + "." + base64UrlEncode("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")
我得到:
ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5.ZXlKemRXSWlPaUl4TWpNME5UWTNPRGt3SWl3aWJtRnRaU0k2SWtwdmFHNGdSRzlsSWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlE=
注意:如果我应该对已经编码的值进行编码,或者按原样使用已经编码的值,我会有些困惑。
(即使用
base64UrlEncode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9") + "." + base64UrlEncode("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")
vs"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
)。无论我应该做什么,最终结果仍然与签名不匹配。我倾向于我不应该重新编码编码值,无论这是真的还是假的。
然后使用HMAC 生成器计算器(https://codebeautify.org/hmac-generator或https://www.freeformatter.com/hmac-generator.html#ad-output)
(不是网站上的实际价值,经过修改以显示这些工具最终会为我构建什么)
HMACSHA256( "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5.ZXlKemRXSWlPaUl4TWpNME5UWTNPRGt3SWl3aWJtRnRaU0k2SWtwdmFHNGdSRzlsSWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlE=", “hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6” )
这让我:
a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01
这与以下的签名部分不匹配JWT
:
wDQ2mU5n89f2HsHm1dluHGNebbXeNr748yJ9kUNDNCAM
!= a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01
目的:
我需要确认这一点的原因是为了证明能够验证JWT
没有被篡改,而无需解码JWT
.
我的客户端 Web 界面不需要解码JWT
,因此他们无需为此安装jwt 包。他们只需要做一个简单的验证,以确认JWT
没有被篡改(尽管不太可能),然后再存储JWT
未来的 API 调用。
解决方案
这都是格式和编码的问题。
在https://jwt.io上,您会根据您的输入值和密码获取此令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
我们要证明签名:
3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
是正确的。
签名是经过 Base64url 编码的 HMAC-SHA256 哈希。(如RFC7515中所述)
当您使用在线 HMAC 生成器计算
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
与秘密
hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6
你得到
de921a2a4b225fd66ff0983e8566eb0f6e1584bdfa84120568da40e1f571dbd3
结果,这是一个 HMAC-SHA256 值,但不是 Base64url 编码的。这个散列是一个大数字的十六进制字符串表示。
要将其与https://jwt.io中的值进行比较,您需要将值从其十六进制字符串表示形式转换回数字并 Base64url 对其进行编码。
以下脚本正在执行此操作,并且还使用 crypto-js 来计算它自己的哈希值。这也可以是您在没有 JWT 库的情况下进行验证的一种方式。
var CryptoJS = require("crypto-js");
// the input values
var base64Header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
var base64Payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";
var secret = "hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6";
// two hashes from different online tools
var signatureJWTIO = "3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M";
var onlineCaluclatedHS256 = "de921a2a4b225fd66ff0983e8566eb0f6e1584bdfa84120568da40e1f571dbd3";
// hash calculation with Crypto-JS.
// The two replace expressions convert Base64 to Base64url format by replacing
// '+' with '-', '/' with '_' and stripping the '=' padding
var base64Signature = CryptoJS.HmacSHA256(base64Header + "." + base64Payload , secret).toString(CryptoJS.enc.Base64).replace(/\+/g,'-').replace(/\//g,'_').replace(/\=+$/m,'');
// converting the online calculated value to Base64 representation
var base64hash = new Buffer.from(onlineCaluclatedHS256, 'hex').toString('base64').replace(/\//g,'_').replace(/\+/g,'-').replace(/\=+$/m,'')
// the results:
console.log("Signature from JWT.IO : " + signatureJWTIO);
console.log("NodeJS calculated hash : " + base64Signature);
console.log("online calulated hash (converted) : " + base64hash);
结果是:
Signature from JWT.IO : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
NodeJS calculated hash : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
online calulated hash (converted) : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
完全相同的!
结论:
不同在线工具计算的值都是正确的,但由于格式和编码不同,无法直接比较。如上所示的一个小脚本可能是一个更好的解决方案。
推荐阅读
- c# - 如何从方法参数的列表中进行选择?
- javascript - IOS 设备中的浏览器不会在后台自动播放声音
- python - Python中如何判断一个多边形是否在另一个多边形内?
- json - 基于属性的 JSON 模式验证
- python - PYODBC/Windows - 如何避免在代码中输入密码?
- c# - 如何统一使用谷歌地图API,C#
- elasticsearch - Lucene 查询中的顺序会影响结果吗?
- javascript - 为什么我不能将此变量中的值添加到我的表中?
- c++ - 如何在我的代码中修复(没有重载函数“getline”的实例与参数列表匹配)
- javascript - 如何正确实现包含 awaitMessages 的循环?