简介
- 介绍: 全名
Json Web Token
, 遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份 - 结构: 由 标头(Header)、有效载荷(Payload)和签名(Signature) 三个段落 组成 (签名可没有)
每个段落用英文句号连接, 且每个段落单独用base64url加密 注: 即使alg为none, 即没有签名, 结尾也需要点号 - Header: 作用: 一般由两个字段组成, 即
alg
和typ
, 也有可选此字段kid
alg
: 指定token加密使用的算法(最常用的为HMAC和RSA算法 -- HS256 RS256 ES256 none)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)
- 服务端: 储存: 验证签名的密钥 (对于对称加密,这是一个密钥;对于非对称加密,这是一个私钥和公钥对) 注: JWT本身并不提供相关任何信息的存储, 而交给服务端自己进行逻辑操作与存储
-
使用:
- 服务端根据登陆状态 将用户信息加密到token中,返给客户端
- 客户端收到服务端返回的token, 存储在cookie中, 并且每次通信都带上token. 服务端解密toke, 验证内容,完成相应逻辑
JWT
的最佳用途是一次性授权Token
, 用于给用户的操作进行标识, 而非给用户的状态进行标识
- 与session的区别: 内容: session会话返回的cookie只用于标识, 本身并没有任何含义; 而JWT包含了用户的相关信息 管理方法: JWT理论上应用于无状态的请求; 而Session由于主要信息储存在客户端, 可用于有状态的请求 跨平台: JWT比较容易跨平台; 而Session基本不能跨平台(得相关平台服务器会话数据互通才可)
--通用漏洞--
未对签名进行验证
- 前提: 服务端未对签名进行验证
- 原理: 服务端可能没有对token签名进行校验, 此时, 攻击者便可任意修改Payload和Header中的值
未对加密算法进行强验证 -- 空加密
- 前提: 生产环境中开启空加密算法, 且不检验alg
- 使用: 只需在header中指定alg为
none
, 然后把signature设置为空(但点号仍旧要在), 服务器不会验证签名
修改加密算法(RSA改为HMAC)
- 前提: 知道RSA公钥, 服务端不验证alg字段
- 原理: HMAC是对称加密算法, 而RSA为非对称算法, 因为加密时的 私钥 基本无法获取, 而进行验证的 公钥 可通过某些方式获取, 所以将RSA改为HMAC加密, 用获得的公钥伪造HMAC签名, 服务端会用公钥进行验证
- 使用: 获得RSA加密公钥后, alg中改为
HS256
, 用公钥伪造HS256签名, 传输
爆破密钥
- 前提: 使用对称加密
- 爆破工具: [[hashcat]] [[jwtcrack]] (hashcat为字典爆破, jwtcrack为暴力爆破,密钥长度五位以上则耗时非常长)
- 爆破后: 爆破后使用对应密钥伪造签名(密钥要进行base64url加密后伪造)
./jwtcrack <token> [alphabet] [max_len] [hmac_alg]
hashcat -a 0 -m 16500 <token> <wordlist>
修改KID参数
- 原理: kid用于读取密钥文件, 若修改该字段的值, 可能造成相关的 文件读取漏洞
- 任意文件读取: 将kid值修改为对应文件的路径, 可读取任意文件 (如 /etc/passwd)