0x00 什么是JWT
JWT的全名是JSON Web Token,利用JSON储存信息,采用签名保证数据的完整性,服务端只储存密钥,用于验证token是否被修改,进而实现用户身份的验证。
0x01 JWT的格式
JWT由三部分组成,分别是
header
、payload
、signature
,每一部分由圆点.
分隔开。
HEADER
上图中的红色部分,即为header
部分
header
中用JSON指明了token的类型和签名所采用的加密算法,然后经过base64URL处理,明文如下:
如图,alg
表示的即为算法,typ
表示的是token的类型
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符
+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法。
PAYLOAD
上图中的紫色部分即为payload
部分
payload
中用JSON表示实际传送的数据,其中有七个官方字段:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
除此以外,还可以自定义字段(如上图中的payload),然后再对其进行base64URL编码,明文如下:
SIGNATURE
上图中的浅蓝色部分即为signature
部分
签名采用了header
中所指定的算法再加上密钥key
进行签名处理,具体如下图所示:
其中123
即是上图JWT所采用的key
图中解析与构造JWT的来源是jwt.io,可用来解析和构造比赛中遇到的JWT
0x03 JWT 的伪造
密钥的爆破
由上文可知,JWT不储存在服务端,所以如果我们可以修改JWT并通过了服务端的验证,有时候就可以获得额外的权限。但是因为JWT有签名保证了数据的完整性,所以我们必须要知道密钥key
,才能做到修改。
好在JWT的头部,只采用base64url,并且其中指定了签名所采用的算法,所以我们可以轻松知道签名算法。如果我么们这时候,可以爆破或者用其他方式获得密钥,那么我们便可以伪造一个JWT用于身份验证。
这里有一个用C语言写成的JWT密钥爆破工具: brendan-rius/c-jwt-cracker
Usage:$ > ./jwtcrack yourJWT
JWT的生成
如果获得了密钥,即可轻松构造出一个JWT。要构造JWT,既可以使用上文所用的jwt.io,也可以使用Python中的pyjwt库,一个脚本如下:
import jwt
token = jwt.encode(
{
"username": "admin",
"password": "1",
},
algorithm = "HS256",
key = "yourKey"
)
print(token)
0x03 从加密算法下手
空加密
有的JWT库支持空加密,即首部中指明签名所采用的算法是None
。这时候,签名就没啥用了,如果开发者在上线了的环境中忘记关闭,那么攻击者提交任何数据都可以通过验证。
要构造加密算法为None
的JWT,并不可以借助jwt.io,因为这通常是恶意的,但是我们依然可以使用上文的Python脚本,提交到服务端的格式为header部分.payload部分.
。
将RS256更改为HS256
HS256是对称加密算法,加密和解密都采用同一密钥。而RS256是非对称加密算法,数据采用公钥加密,私钥解密。所以要通过一个使用了RS256加密的JWT验证,不仅要知道公钥,还需要知道私钥,但一般来说私钥是很难有机会获取的,但公钥却是比较容易获得的。
因此,我们可以利用试想一下,如果一个原本采用RS256的JWT,被我们改为了HS256并知晓了公钥,这时服务端就会使用同一个密钥进行解密,也就是使用我们所获得公钥进行验证,这样便通过了验证。
0x04 利用首部可选参数kid
什么是kid
kid
是JWT首部的一个可选参数,全名为KEY ID
,用来标识验证token该使用哪一个密钥。
SQL注入
如果服务端使用kid进行了数据的查询,则可能会存在SQL的问题。
"kid": "foobar' union select 'hackerkey'"
由于序号为foobar
的密钥并不存在,所以联合查询会返回后面的hackerkey
,这样就将密钥变成了可控的了。
kid还可能造成RCE和目录遍历,不过我就先不写了😃;还有修改参数jku和x5u的,感兴趣的话自己查吧。
0x05参考文章
浅谈JWT绕过 - Von的博客 | Von Blog (v0n.top)
攻击JWT的一些方法 - 先知社区 (aliyun.com)
JSON Web Token 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)
对jwt的安全测试方式总结 - SAUCERMAN (saucer-man.com)