发现问题
在测试 node-jsonwebtoken
的使用方式
javascript
import { sign, verify } from 'jsonwebtoken';
const token = sign({ foo: 'bar' }, 'secret');
console.log(token);
console.log(verify(token, 'secret'));
console.log(verify(token, 'incorret_secret'));
生成的 jwt 是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MDYwNjE1MTB9.LQJzaFCIyMGW8CIni59LtGb32BkXVzsQSY2iRfhlnBU
在incorret_secret
这里会报:JsonWebTokenError: invalid signature
错误,说签名错误
突发奇想,想拿着生成好的 jwt 验证一下是否可以解析出来,就打开了jwt.io 复制过去之后,发现我的 payload 也就是 { foo: 'bar' }
是可以查看的,如下图:
我最初以为我在加密之后,别人是不能查看的,上面的结果和我的理解不一致,我以为别人是不知道我的 payload
的。
jwt 的 payload 是不加密的
jwt的结构是三段式的,中间用了两个.
隔开了,后来我发现其实前两段都是 base64
编码后的值:
HEADER 表明了使用的算法和类型
json
{
"alg": "HS256",
"typ": "JWT"
}
payload 是想传递的信息包:
json
{
"foo": "bar",
"iat": 1706061510
}
第三段的 Signature
是真正被加密的:使用算法将上面的信息做加密
scss
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
验证和最终结论
通过以上的信息,知道了真正加密的部分只有 Signature
部分。Signature
用于验证消息在发送过程中没有被更改,也可以验证 secret
是否有效。
javascript
import { sign, verify } from 'jsonwebtoken';
const token = sign({ foo: 'bar' }, 'secret');
console.log(token);
console.log(
verify(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXJyIiwiaWF0IjoxNzA2MDY0NjU0fQ==.n4Wwcf1zYfZfcVg9HNzrnxeYi2xGThNxgQUWrD2x6xI',
'secret',
),
);
我这里更改了 payload 的部分,就会报错:JsonWebTokenError: invalid token
,更改 header
部分也一样
scss
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
根据上面的公式和运行结果来看,无论 header
、payload
和 secret
哪一个对不上,都会导致解析失败,jwt 的验证不是对内容的解析,而是保证内容没有更改过。