JWT的全称是Json Web Token。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。
JWT由三个部分组成:header.payload.signature
header部分最常用的两个字段是alg
和typ
,alg
指定了token加密使用的算法(最常用的为HMAC和RSA算法),typ
声明类型为JWT。
payload则为用户数据以及一些元数据有关的声明,用以声明权限。
signature的功能是保护token完整性。
生成方法为将header和payload两个部分联结起来,然后通过header部分指定的算法,计算出签名。
抽象成公式就是
signature = HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)
值得注意的是,编码header和payload时使用的编码方式为base64urlencode
,base64url
编码是base64
的修改版,为了方便在网络中传输使用了不同的编码表,它不会在末尾填充”=”号,并将标准Base64中的”+”和”/“分别改成了”-“和”-“。
完整token生成
在线
Python
python的Pyjwt
使用示例:
1 | import jwt |
攻击方式
空加密算法
JWT支持使用空加密算法,可以在header中指定alg为None
这样的话,只要把signature设置为空(即不添加signature字段),提交到服务器,任何token都可以通过服务器的验证。举个例子,使用以下的字段
1 | { |
生成的完整token为ew0KCSJhbGciIDogIk5vbmUiLA0KCSJ0eXAiIDogImp3dCINCn0.ew0KCSJ1c2VyIiA6ICJBZG1pbiINCn0
(header+’.’+payload,去掉了’.’+signature字段)
空加密算法的设计初衷是用于调试的,但是如果某天开发人员脑阔瓦特了,在生产环境中开启了空加密算法,缺少签名算法,jwt保证信息不被篡改的功能就失效了。攻击者只需要把alg字段设置为None,就可以在payload中构造身份信息,伪造用户身份。
修改RSA加密算法为HMAC
JWT中最常用的两种算法为HMAC
和RSA
。
HMAC
是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,它是一种对称加密算法,使用相同的密钥对传输信息进行加解密。
RSA
则是一种非对称加密算法,使用私钥加密明文,公钥解密密文。
在HMAC和RSA算法中,都是使用私钥对signature
字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token。
现在我们假设有这样一种情况,一个Web应用,在JWT传输过程中使用RSA算法,密钥pem
对JWT token进行签名,公钥pub
对签名进行验证。
1 | { |
通常情况下密钥pem
是无法获取到的,但是公钥pub
却可以很容易通过某些途径读取到,这时,将JWT的加密算法修改为HMAC,即
1 | { |
同时使用获取到的公钥pub
作为算法的密钥,对token进行签名,发送到服务器端。
服务器端会将RSA的公钥(pub
)视为当前算法(HMAC)的密钥,使用HS256算法对接收到的签名进行验证。
1 | #node.js |
RSA算法双token生成公钥
先生成两个token,然后利用rsa_sign2n工具来生成公钥:
1 | python3 jwt_forgery.py [JWT1] [JWT2] |
通过测试得到正确公钥文件,可进一步利用RsaCtfTool得到私钥(或修改RSA加密算法为HMAC):
1 | python3 RsaCtfTool.py --public [PEM] --private |
参考:
爆破密钥
对 JWT 的密钥爆破需要在一定的前提下进行:
- 知悉JWT使用的加密算法
- 一段有效的、已签名的token
- 签名用的密钥不复杂(弱密钥)
所以其实JWT 密钥爆破的局限性很大。
相关工具:
./gojwtcrack -t token.txt -d rockyou.txt
./jwtcrack [JWT]
python3 jwt_tool.py [JWT]
python3 CrackJWT.py jwt_str keys.txt
其他
pyjwt包-jwt伪造 (CVE-2022-39227)
影响版本:pyjwt<3.3.4
代码:
1 | import base64 |
EXP:
1 | # 官方:https://github.com/davedoesdev/python-jwt/blob/88ad9e67c53aa5f7c43ec4aa52ed34b7930068c9/test/vulnerability_vows.py |
参考:
2022祥云杯 - FunWEB
NewstarCTF 2023 - Ye’s Pickle