简介
- 介绍: 全名
Json Web Token, 遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份 - 结构:
Header.Payload.Signature(每个段落单独用base64url加密)
注: 即使alg为"none", 即没有签名(jwt允许无签名), 结尾也需要点号 - Header:
作用: 一般由alg和typ两个字段组成, 也有可选字段kid
alg: 指定token加密使用的算法
typ: 指定令牌的类型, 值基本为JWT
kid: 指定使用的加密算法的密钥 在服务端的位置 - Payload:
作用: 储存着用户数据以及一些元数据有关的声明, 声明有三种(注册声明 公共声明 私有声明)
注册声明: 由JWT系统自身预定义的声明iss (Issuer): 令牌的发行者sub (Subject): 令牌的主题aud (Audience): 令牌的接收者exp (Expiration Time): 过期时间nbf (Not Before): 在此之前不可用iat (Issued At): 发行时间jti (JWT ID): 唯一标识符
公共声明: 由使用JWT的人自由定义, 用于传递 非敏感信息
私有声明: 由使用JWT的人自由定义, 用于传递 敏感信息
- Signature:
作用: 用于保护token完整性, 验证消息在传输过程中没有被更改,- 注: 并且对于使用私钥签名的token,它还可以验证JWT的发送方
生成方法: 将header和payload两部分base64urlEncode后联结起来, 再用header指定的算法, 计算出签名 - 即如
HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)
- 注: 并且对于使用私钥签名的token,它还可以验证JWT的发送方
- 服务端:
储存: 验证签名的密钥 (对于对称加密,这是一个密钥;对于非对称加密,这是一个私钥和公钥对)
注: JWT本身并不提供相关任何信息的存储, 而交给服务端自己进行逻辑操作与存储 - 使用:
- 服务端根据登陆状态 将用户信息加密到token中,返给客户端
- 客户端收到服务端返回的token, 存储在cookie中, 并且每次通信都带上token. 服务端解密toke, 验证内容,完成相应逻辑
JWT的最佳用途是一次性授权Token, 用于给用户的操作进行标识, 而非给用户的状态进行标识
- 与session的区别:
内容: session会话返回的cookie只用于标识, 本身并没有任何含义; 而JWT包含了用户的相关信息
管理方法: JWT理论上应用于无状态的请求; 而Session由于主要信息储存在客户端, 可用于有状态的请求
跨平台: JWT比较容易跨平台; 而Session基本不能跨平台(得相关平台服务器会话数据互通才可) - 常见算法
HS(HMAC-SHA): 对称加密, 有HS256 HS384 HS512
RS(RSA-SHA): 非对称加密, RS256 RS384 RS512
ES(ECDSA-SHA): 非对称加密, 有ES256 RS384 ES512
PS(RSA-PSS-SHA256): 非对称加密, 有PS256 PS384 PS512
-- 通用漏洞 --
普通
- 信息泄露: jwt中可能包含敏感信息, 解码后查看
解码: https://jwt.io/ 或 手动base64url解码 - 未对签名进行验证: 可任意修改Payload和Header中的值(因为不会校验签名)
空加密 -- 未对加密算法进行强验证
- 前提: 生产环境中开启空加密算法, 且不检验alg/使用alg字段来决定算法
- 使用: 将alg字段值改为
"none"(可大小写绕过), 删除签名(点号仍需保留)
爆破密钥
- 前提: 使用对称加密(HS256 HS384 HS512)
- 爆破工具: hashcat jwtcrack john
- hashcat(字典爆破):
hashcat -a 0 -m 16500 <token> <wordlist> - jwt-cracker:
暴力破解:jwt-cracker -t <token> -a [alphabet] --max [max_len]
字典爆破:jwt-cracker -t <token> -d <wordlist>
下载:npm install --global jwt-cracker
注: 暴力破解五位以上的密钥将会特别慢 - 爆破后: 爆破后使用对应密钥伪造签名(密钥要进行base64url加密后伪造)
修改加密算法 (非对称加密改为HMAC)
- 前提: 知道非对称加密公钥, 且不检验alg/使用alg字段来决定算法
- 原理:对于非对称加密, 私钥用于加密, 公钥用于验证, 若改为HMAC加密(对称加密), 用获得的公钥伪造HMAC签名, 服务端会用公钥进行验证
注: 私钥相对难获取, 公钥相对易获取 - 使用: 获得非对称加密公钥后, alg改为
HS256, 用公钥伪造HS256签名, 传输 - 注: 当伪造签名时, 公钥内容并非只有一行, 所以需要将换行符也算进去进行base64url编码后填入burpsuite的JWT Editor的k字段中
伪造签名
- 工具: 使用burpsuite的JWT Editor工具
- 普通:
import jwt payload = {"alg":"None","typ":"jwt"} headers = { "iss":"admin","iat":1718865117,"exp":1718872317,"nbf":1718865117,"sub":"admin","jti":"503a4a179e5645e7be5c19a88450c618" } key = "" print(jwt.encode(payload, ,key algorithm="HS256", headers=headers))
KID参数注入
- 前提: 服务端通过kid字段来决定校验的密钥
- 原理: kid用于决定校验时使用的密钥文件, 若修改该字段的值, 可能造成 目录遍历漏洞/伪造签名/其它漏洞
- 目录遍历: 将kid值修改为对应文件的路径, 对目录进行爆破
- 伪造签名: 将kid设置为内容已知的文件的路径, 即可知道密钥, 从而伪造签名
如将kid设置为/dev/null, 即可将密钥设置为空, 用空密钥伪造签名 - 其它漏洞: 跟读取kid的方式有关系
若密钥存在数据库中, 服务端通过数据库搜寻kid读取密钥, 则可能有SQL注入
若密钥通过命令执行来读取, 而非文件函数, 则存在RCE漏洞
CVE-2022-39227
- 简介: python_jwt<3.3.4时, 其库中的verify_jwt()函数身份验证可绕过