如何使用在线工具手动验证 JWT 签名 [英] How to manually validate a JWT signature using online tools
问题描述
据我所知,验证 JWT
签名是一个简单的过程.但是当我使用一些在线工具为我做这件事时,它不匹配.如何在不使用 JWT 库的情况下手动验证 JWT
签名?我需要一个快速的方法(使用可用的在线工具)来演示这是如何完成的.
我在 https://jwt.io/#debugger- 上创建了我的 JWT
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-生成器 或 https://www.freeformatter.com/hmac-generator.html#ad-output)
(不是网站的实际价值,已修改以显示工具最终将为我构建的内容)
<上一页>HMACSHA256("ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5.ZXlKemRXSWlPaUl4TWpNME5UWTNPRGt3SWl3aWJtRnRaU0k2SWtwdmFHNGdSRzlsSWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlE=",hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6")这让我很感动:
<上一页>a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01这与 JWT
的签名部分不匹配:
wDQ2mU5n89f2HsHm1dluHGNebbXeNr748yJ9kUNDNCAM
!= a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01
目的:
我需要确认这一点的原因是为了证明能够验证 JWT
未被篡改,而无需解码 JWT
.p>
我的客户端 Web 界面不需要解码 JWT
,因此他们无需为此安装 jwt 包.他们只需要在存储 JWT
以供将来的 API 调用之前进行简单的验证,以确认 JWT
没有被篡改(尽管不太可能).
都是格式和编码的问题.
在 https://jwt.io 上,您会根据您的输入值和密码获得此令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFa
我们要证明签名:
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");//输入值var base64Header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";var base64Payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";var secret = "hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6";//来自不同在线工具的两个哈希var signatureJWTIO = "3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M";var onlineCaluclatedHS256 = "de921a2a4b225fd66ff0983e8566eb0f6e1584bdfa84120568da40e1f571dbd3";//使用 Crypto-JS 进行哈希计算.//两个replace表达式通过replace将Base64转换为Base64url格式//'+' 和 '-','/' 和 '_' 并去除 '=' 填充var base64Signature = CryptoJS.HmacSHA256(base64Header + "." + base64Payload , secret).toString(CryptoJS.enc.Base64).replace(/+/g,'-').replace(///g,'_').replace(/=+$/m,'');//将在线计算的值转换为 Base64 表示var base64hash = new Buffer.from(onlineCaluclatedHS256, 'hex').toString('base64').replace(///g,'_').replace(/+/g,'-').replace(/=+$/m,'')//结果:console.log("来自 JWT.IO 的签名:" + signatureJWTIO);console.log("NodeJS 计算哈希:" + base64Signature);console.log("在线计算哈希(转换):"+base64hash);
结果是:
来自 JWT.IO 的签名:3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29MNodeJS计算哈希:3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M在线计算哈希(转换):3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
一模一样!
结论:
不同在线工具计算的值都是正确的,但由于格式和编码不同,无法直接比较.如上所示的一个小脚本可能是一个更好的解决方案.
From what I can understand, it's a straight forward process to validate a JWT
signature. But when I use some online tools to do this for me, it doesn't match. How can I manually validate a JWT
signature without using a JWT library? I'm needing a quick method (using available online tools) to demo how this is done.
I created my JWT
on https://jwt.io/#debugger-io with the below info:
- Algorithm:
HS256
- Secret:
hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6
- Header:
{ "alg": "HS256", "typ": "JWT" }
- Payload:
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
- Verify Signature (section):
- Secret value changed to above
- "Checked" secret base64 encoded (whether this is checked or not, still get a different value)
JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.wDQ2mU5n89f2HsHm1dluHGNebbXeNr748yJ9kUNDNCA
Manual JWT
signature verification attempt:
Using a base64UrlEncode calculator (http://www.simplycalc.com/base64url-encode.php or https://www.base64encode.org/)
If I: (Not actual value on sites, modified to show what the tools would ultimately build for me)
base64UrlEncode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9") + "." + base64UrlEncode("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")
I get:
ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5.ZXlKemRXSWlPaUl4TWpNME5UWTNPRGt3SWl3aWJtRnRaU0k2SWtwdmFHNGdSRzlsSWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlE=
NOTE: there's some confusion on my part if I should be encoding the already encoded values, or use the already encoded values as-is.
(i.e. using
base64UrlEncode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9") + "." + base64UrlEncode("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")
vs"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
).Regardless on which I should do, the end result still doesn't match the signature. I'm leaning towards that I should NOT re-encode the encoded value, whether that's true or not.
Then using a HMAC Generator calculator (https://codebeautify.org/hmac-generator or https://www.freeformatter.com/hmac-generator.html#ad-output)
(Not actual value on sites, modified to show what the tools would ultimately build for me)
HMACSHA256( "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5.ZXlKemRXSWlPaUl4TWpNME5UWTNPRGt3SWl3aWJtRnRaU0k2SWtwdmFHNGdSRzlsSWl3aWFXRjBJam94TlRFMk1qTTVNREl5ZlE=", "hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6" )
Which gets me:
a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01
And that doesn't match the signature portion of the JWT
:
wDQ2mU5n89f2HsHm1dluHGNebbXeNr748yJ9kUNDNCAM
!= a2de322575675ba19ec272e83634755d4c3c2cd74e9e23c8e4c45e1683536e01
Purpose:
The reason I'm needing to confirm this is to prove the ability to validate that the JWT
hasn't been tampered with, without decoding the JWT
.
My clients web interface doesn't need to decode the JWT
, so there's no need for them to install a jwt package for doing that. They just need to do a simple validation to confirm the JWT
hasn't been tampered with (however unlikely that may be) before they store the JWT
for future API calls.
It's all a matter of formats and encoding.
On https://jwt.io you get this token based on your input values and secret:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
We want to prove that the signature:
3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
is correct.
The signature is a HMAC-SHA256 hash that is Base64url encoded. (as described in RFC7515)
When you use the online HMAC generator to calculate a hash for
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
with the secret
hONPMX3tHWIp9jwLDtoCUwFAtH0RwSK6
you get
de921a2a4b225fd66ff0983e8566eb0f6e1584bdfa84120568da40e1f571dbd3
as result, which is a HMAC-SHA256 value, but not Base64url encoded. This hash is a hexadecimal string representation of a large number.
To compare it with the value from https://jwt.io you need to convert the value from it's hexadecimal string representation back to a number and Base64url encode it.
The following script is doing that and also uses crypto-js to calculate it's own hash. This can also be a way for you to verify without JWT libraries.
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);
The results are:
Signature from JWT.IO : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
NodeJS calculated hash : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
online calulated hash (converted) : 3pIaKksiX9Zv8Jg-hWbrD24VhL36hBIFaNpA4fVx29M
identical!
Conclusion:
The values calculated by the different online tools are all correct but not directly comparable due to different formats and encodings. A little script as shown above might be a better solution.
这篇关于如何使用在线工具手动验证 JWT 签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!