JSON WEB TOKEN安全

0x00 JWT是什么
JWT全称JSON WEB Token,可以理解为一个小型的协议,用于客户端和服务端可靠地传输数据。
一个JWT串(来自maimai)实际上长成这个样子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1IjozNDcyMjU4NiwiaWQiOjc3Mjk3NTl9.I3p2MonJyAAMdsk4VyKgrQT6jal4jJSJv09BCbzOcNw
是一个以点号分割的三个子串拼接起来的。
JWT串的组成分为三个部分:
(1)头部
{
"typ": "JWT",
"alg": "HS256"
}
alg用于指定后端用什么方式进行签名校验,默认使用的是HS256,也就是HMAC-SHA256。将上面的串进行base64编码后作为真正填充的头部。

(2)载荷
这里的载荷其实就是一些用户数据的声明,分为公有声明、私有声明、注册声明。可以理解为K-V形式的用户数据存储。比如:
{
"iat": 1441593502,
"username": "admin"
}
将上面的串进行base64编码后作为真正填充的载荷。

(3)签名
签名是有很多种算法考虑的,有哈希也有非对称加密方式。这里是对base64后的头和载荷进行签名计算,计算完成后base64一遍然后用点号拼接到JWT串的最后面。

当服务器端收到一个JWT串时,毫无疑问首先要对其进行分解,之后根据头部提供的方式来进行签名校验,校验无误之后再进行后续的操作。

0x01 安全问题
和当年的OAuth2.0协议一样,虽然RFC规定的还不错,但是业务上实现的时候容易出疏漏。
有两个问题:
(1)签名方式为None
历史上很多类库支持设置签名方式为None的情况,比如下面这种:
{
"typ": "JWT",
"alg": "None"
}
比如历史上py-jwt实现中,就有这个问题:
JSON WEB TOKEN安全
攻击方法很简单,将header部分的alg改为None,然后将签名部分删除掉,形如:
xxxxxx.xxxxxx.
然后提交,就可以绕过签名机制。

(2)使用非对称加密方式
如果在后端的签名校验中,使用了RSA算法,即私钥加密,公钥解密的方式实现签名校验。但是有一个问题,攻击者可以在前端指定任意签名算法,如果这时候指定为HMAC-SHA256的方式,后端校验解密签名的时候实际上用的key就是公钥,而这个公钥一般在客户端都可以拿到。那么,就可以让攻击者在客户端用这个公钥伪造一个签名,从而绕过这个校验机制。

相关文章: