jwt组成及漏洞利用详解
[TOC]
JWT 全称是 JSON Web Token ,是一种基于 JSON 的轻量级身份认证和信息交换规范,核心作用是在客户端和服务器之间安全传递声明(如用户身份信息)
JWT 的核心构成
JWT 由三部分组成,通过 . 连接,格式为 Header.Payload.Signature :
1.Header(头部) :指定 JWT 使用的算法(如 HS256、RS256)和令牌类型。
2.Payload(载荷) :存储需要传递的声明信息(如用户 ID、过期时间),默认不加密,仅做 Base64 编码。
3.Signature(签名) :用 Header 中指定的算法,结合密钥对 Header 和 Payload
进行签名,确保内容不被篡改。
Header
作用:描述 JWT 的元数据,如签名算法和令牌类型。
内容:一个 JSON 对象,通常包含两个字段:
alg:签名算法(如 HMAC SHA256、RSA 等)。
typ:令牌类型(固定为 JWT)。
示例:
1 | { |
编码:Base64Url 编码后形成 Header 部分。
Payload
标准声明:
iss(issuer):签发者sub(subject):主题,通常是用户IDaud(audience):接收方exp(expiration time):过期时间(时间戳)iat(issued at):签发时间(时间戳)nbf(not before):生效时间(时间戳)jti(JWT ID):JWT唯一标识符
示例:
1 | { |
编码:Base64Url 编码后形成 Header 部分。
Signature
签名用于验证消息在传输过程中没有被篡改,对于使用私钥签名的令牌,它还可以验证JWT的发送者是否为它所声称的发送者。
**签名生成过程: **
1 | signature = algorithm( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) |
JWT 算法的可逆与不可逆分类
JWT 的算法主要分为 对称加密算法 和 非对称加密算法 ,二者的核心区别在于是否使用
“单一密钥”,这直接决定了算法的可逆性。
不可逆算法(核心用于签名验证)
这类算法仅能从 “原文” 生成 “签名”,无法从 “签名” 反推回 “原文”,核心作用是 验证数据完整性 ,而非加密。
对称加密签名算法 :使用同一个密钥(Secret Key)进行签名和验证,常见算法包括:
- HS256(HMAC with SHA-256)
- HS384(HMAC with SHA-384)
- HS512(HMAC with SHA-512)
**非对称加密签名算法 ** :使用 “私钥” 签名、“公钥” 验证,私钥仅保存在服务器,公钥可公开,常见算法包括:
- RS256(RSA with SHA-256)
- RS384(RSA with SHA-384)
- RS512(RSA with SHA-512)
- ES256(ECDSA with SHA-256)
- ES384(ECDSA with SHA-384)
- ES512(ECDSA with SHA-512)
公钥:public key (一般会存在在响应包当中,在登陆时由客户端发送申请公钥的请求)
形式一般为:
1 | ————————publickey—————————————— |
私钥:一般存在后端服务器中,不会暴露在 web 服务器,极少数将私钥写在 js 文件中(尝试伪造)
对于 jwt 进行伪造, RS/ES 系列算法因私钥仅存服务器,即使公钥泄露,攻击者也无法伪造签名,安全性远高于 HS 系列。
对于 HS 系列的算法来说,因为仅为 单一密钥, 就可能存在风险:
- 密钥复用风险 :同一密钥同时负责签名生成和验证,一旦密钥泄露(如代码硬编码、配置文件泄露),攻击者可直接伪造合法 JWT。
- 爆破可行性 :如果密钥强度不足(如长度过短、使用弱口令、属于常见字典词),攻击者可通过以下方式爆破:
(1)收集合法 JWT(Header+Payload+Signature);
(2)使用字典或暴力枚举可能的密钥,对 Header 和 Payload 重新计算签名;
(3)对比计算出的签名与 JWT 中的 Signature,一致则说明密钥正确。
例如,若密钥是简单的 “123456” 或 “secret”,借助 Hashcat 等工具,几分钟内就能爆破成功。而 HS512 虽比 HS256
计算成本高,但本质上仍无法抵御强密钥的爆破(只是延长了爆破时间)。
常见攻击手法
alg 修改为 none 的无签名攻击
原理: JWT 标准中定义了
alg: "none"表示 “不使用签名”,部分实现(如早期的jsonwebtoken库)未严格校验这一选项,允许攻击者将 Header 中的alg修改为none(大小写不敏感,如None/NoNe/NONE),同时删除 Signature 部分,使服务器跳过签名验证直接信任 Payload。攻击步骤:
- 截取合法 JWT,解码 Header,将
alg改为none; - 修改 Payload(如篡改用户角色、权限);
- 删除 Signature 部分(格式变为
Header.Payload.,末尾保留.); - 提交伪造的 JWT,服务器若未校验
alg: "none"的合法性,会直接采信 Payload。
- 截取合法 JWT,解码 Header,将
**影响:**可直接篡改用户身份、权限等核心信息,无需知晓密钥。
未验证签名攻击
- 原理: 服务器在验证 JWT 时,因代码逻辑缺陷(如未调用签名验证函数、条件判断错误),直接跳过签名校验步骤,仅解析 Payload 内容。
- 攻击方式: 无需修改
alg,直接篡改 Payload(如将"role":"user"改为"role":"admin"),重新 Base64 编码后提交,服务器会直接信任篡改后的内容。 - 特点: 比
alg: none更直接,属于开发层面的低级错误,常见于自定义 JWT 实现中。
JWKS 公钥注入伪造攻击
- 背景: 部分系统使用 JWKS(JSON Web Key Set,公钥集合)自动获取验证 JWT 的公钥,JWKS 通常通过 URL(如
/.well-known/jwks.json)提供。 - 原理: 漏洞存在于 Cisco 的某些设备中,允许攻击者控制 JWKS 的 URL,注入自定义公钥,导致服务器使用攻击者提供的公钥验证签名,从而伪造任意 JWT。
- 攻击步骤:
- 攻击者生成一对 RSA 密钥(私钥用于签名,公钥用于注入);
- 控制服务器获取 JWKS 的来源,将自定义公钥写入 JWKS;
- 使用私钥对篡改后的 Payload 签名,生成伪造 JWT;
- 服务器从恶意 JWKS 获取公钥,验证通过并信任伪造内容。
空签名攻击
- 原理: 针对使用非对称算法(如 RS256)的 JWT,部分实现对 “空签名”(Signature 字段为空)的处理存在缺陷。攻击者可将
alg设为非对称算法(如 RS256),同时将 Signature 设为空,服务器若错误地将空签名视为 “验证通过”,则会信任篡改后的 Payload。 - 区别于
alg: none:此处alg仍为签名算法(如 RS256),但签名值为空,利用服务器对空签名的逻辑漏洞绕过验证。
算法混淆攻击
**原理:**利用对称算法(HS256)和非对称算法(RS256)的验证逻辑差异,欺骗服务器用错误的密钥验证签名。
例如,服务器本应使用 RS256(私钥签名、公钥验证),但攻击者将
alg改为 HS256,并使用服务器的 公钥 作为 HS256 的对称密钥对篡改后的 Payload 签名。 若服务器错误地用公钥(而非私钥)验证 HS256 签名(把公钥当对称密钥用),则会验证通过。**攻击条件:**服务器同时支持 HS256 和 RS256,且公钥可被攻击者获取(如通过 JWKS 公开)。
密钥泄露导致
原理: 若服务器的对称密钥(HS 系列)或私钥(RS/ES 系列)泄露(如硬编码在代码、配置文件泄露、日志泄露),攻击者可直接用泄露的密钥生成合法签名,篡改 Payload 后伪造 JWT。
常见泄露场景:
(1)开源项目代码中硬编码密钥(如
secret=123456);(2)密钥存储在前端代码(如 JavaScript 文件)中;
(3)密钥通过错误配置被写入日志文件。
(exp)篡改攻击
- 原理:
exp(过期时间)是 Payload 中的标准声明,用于指定 JWT 的有效期。若服务器未验证exp字段(或验证逻辑错误,如时区处理不当),攻击者可篡改exp为未来时间,使过期的 JWT 仍能被使用。 - 案例: 某系统仅检查
exp是否存在,未实际对比当前时间,攻击者将exp改为9999999999(远未来时间),使过期 JWT 永久有效。
Base64 编码漏洞
- 原理: JWT 的 Header 和 Payload 使用 Base64URL 编码(无 Padding 或允许任意 Padding),部分实现对编码格式校验不严,攻击者可通过篡改编码后的字符串(而非解码后的 JSON),实现 Payload 篡改且签名 “看似有效”。
- 案例: 修改 Base64URL 编码后的 Payload 字符串(如替换某个字符),使其解码后恰好为目标内容(如
"role":"admin"),而服务器未重新编码验证,直接信任解码结果。
判断 JWT 的构造及利用方式
如果 JWT 结合了多因子校验(即验证逻辑依赖多个独立因子,而非单一 JWT 本身),那么单纯篡改 JWT 中的某一个因子(如 Payload内容、签名算法等)很可能无法绕过整体验证,攻击成功率会大幅降低。
JWT 签名 + 服务器端状态校验
- 场景: 服务器不仅验证 JWT 的签名和内容,还会查询后端存储(如 Redis、数据库)中该 JWT 的状态(如是否被吊销、是否与用户当前会话匹配)。
- 攻击限制: 即使攻击者通过
alg: none或空签名篡改了 JWT 的 Payload(如提升权限),服务器查询后端状态时会发现 “该 JWT 的权限信息与存储的原始记录不符”,从而拒绝请求。 例如:用户登录时生成的 JWT 对应role:user,服务器在 Redis 中记录了该 JWT 的唯一 ID 及其真实权限,篡改 JWT 的role为admin后,服务器对比 Redis 记录会发现不一致,直接拦截。
JWT 签名 + 短期有效期(exp) + 动态 Token or uuid 绑定
- 场景: JWT 的
exp设置为极短时间(如 1 分钟),同时客户端需定期用 “刷新 Token”(独立于 JWT,且存储在服务器)获取新 JWT,且刷新 Token 与用户 IP / 设备绑定。使用 uuid 则因为 uuid 极其难以遍历。 - 攻击限制: 即使攻击者篡改了 JWT 的
exp延长有效期,或伪造了签名,由于 JWT 本身很快过期,且刷新 Token 与攻击者的 IP / 设备不匹配,无法获取新的有效 JWT,攻击窗口极短。
JWT + 附加校验参数(如客户端指纹、请求上下文)
- **场景:**JWT 的 Payload 中包含客户端指纹(如浏览器 UA、设备 ID 的哈希值),服务器验证时不仅检查 JWT 签名,还会对比当前请求的客户端指纹与 Payload 中的记录是否一致。




