JWT原理及常见漏洞详解

JWT原理及常见漏洞详解

小话安全 小话安全 2025-05-22 11:11

一、JWT原理

JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息。它通常用于身份验证(Authentication)和授权(Authorization),特别是在分布式系统和无状态服务中。以下是其核心原理和组成部分的详细介绍:

1. JWT 的组成

JWT 由三部分组成,以点号 .
 分隔,形式为:Header.Payload.Signature

(1) Header(头部)

  • 作用
    :描述 JWT 的元数据,如签名算法和令牌类型。

  • 内容
    :一个 JSON 对象,通常包含两个字段:

  • alg
    :签名算法(如 HMAC SHA256、RSA 等)。

  • typ
    :令牌类型(固定为 JWT
    )。

  • 示例

json

  • “`

- **编码**  
:Base64Url 编码后形成 Header 部分。  

#### (2) Payload(负载)  
- **作用**  
:携带实际的数据(如用户身份、权限等),称为“声明”(Claims)。  

- **内容**  
:分为三类声明:  

- iss  
(签发者)、exp  
(过期时间)、sub  
(主题)、aud  
(受众)等。  

- **注册声明(Registered Claims)**  
:预定义的标准化字段(非强制但建议使用),例如:  

- **公共声明(Public Claims)**  
:自定义字段,但需避免与已有声明冲突。  

- **私有声明(Private Claims)**  
:服务间协商的自定义字段。  

- **示例**  
:  

json  

- ```
  • 编码
    :Base64Url 编码后形成 Payload 部分。

(3) Signature(签名)

  • 作用
    :验证令牌的完整性和来源的真实性,防止数据篡改。

  • 生成方式
    :将 Header 和 Payload 的 Base64Url 编码结果用 .
     连接,再使用 Header 中指定的算法和密钥(Secret)进行签名。

  • 示例
    (HMAC SHA256 算法):

js

  • “`

- **验证方式**  
:接收方用相同算法和密钥重新计算签名,与 JWT 中的签名比对。  

### 2. JWT 的工作流程  
1. **用户登录**  
:客户端发送凭证(如用户名密码)到认证服务器。  

1. **生成 JWT**  
:服务器验证凭证后,生成 JWT 并返回给客户端。  

1. **客户端存储**  
:客户端(如浏览器)将 JWT 保存在本地(如 LocalStorage 或 Cookie)。  

1. **发送 JWT**  
:客户端在后续请求的 Authorization  
 头中附带 JWT(格式:Bearer <token>  
)。  

1. **服务器验证**  
:服务器验证 JWT 的签名和有效期,并处理请求。  

### 3. JWT 的核心特性  
- **无状态(Stateless)**  
:服务端无需存储会话信息,所有数据包含在令牌中。  

- **自包含(Self-contained)**  
:Payload 可直接解析出用户信息,减少数据库查询。  

- **跨域支持**  
:适用于分布式系统和跨域场景(如单点登录 SSO)。  

- **安全性**  
:通过签名防篡改,但需结合 HTTPS 防止令牌泄露。  

### 4. 安全性注意事项  
1. **密钥保护**  
:签名密钥(Secret)必须严格保密,泄露将导致令牌可被伪造。  

1. **敏感数据**  
:Payload 仅 Base64 编码,非加密!**切勿存储密码等敏感信息**  
。  

1. **有效期控制**  
:设置合理的 exp  
 过期时间,避免长期有效的令牌。  

1. **HTTPS 传输**  
:防止令牌在传输过程中被窃取(如中间人攻击)。  

1. **算法选择**  
:避免使用弱算法(如 none  
 或 HS256  
 密钥过短)。  

### 5. JWT 的常见应用场景  
- 用户身份认证(替代 Session-Cookie 模式)。  

- API 接口鉴权(如 OAuth 2.0 的 Bearer Token)。  

- 服务间安全通信(微服务架构)。  

- 单点登录(SSO)系统。  

### 6. JWT 的优缺点  
<table><thead><tr><th style="color: rgb(64, 64, 64);padding: 10px 10px 10px 0px;border-bottom: 1.11111px solid rgb(187, 187, 187);border-top: none;font-weight: 600;font-size: 15px;line-height: 1.72;border-right-color: rgb(187, 187, 187);border-left-color: rgb(187, 187, 187);text-align: left;"><strong><span leaf=""><span textstyle="" style="font-size: 15px;">优点</span></span></strong></th><th style="color: rgb(64, 64, 64);padding: 10px;border-bottom: 1.11111px solid rgb(187, 187, 187);border-top: none;font-weight: 600;font-size: 15px;line-height: 1.72;border-right-color: rgb(187, 187, 187);border-left-color: rgb(187, 187, 187);text-align: left;"><strong><span leaf=""><span textstyle="" style="font-size: 15px;">缺点</span></span></strong></th></tr></thead><tbody><tr><td style="padding: 10px 10px 10px 0px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">无状态,适合分布式系统</span></span></section></td><td style="padding: 10px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">令牌一旦签发,无法直接废止(需依赖短有效期或黑名单)</span></span></section></td></tr><tr><td style="padding: 10px 10px 10px 0px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">减少数据库查询(自包含数据)</span></span></section></td><td style="padding: 10px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">Payload 数据过大可能影响性能</span></span></section></td></tr><tr><td style="padding: 10px 10px 10px 0px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">跨语言、跨平台支持</span></span></section></td><td style="padding: 10px;border-bottom: 1.11111px solid rgb(229, 229, 229);font-size: 15px;line-height: 1.72;border-top-color: rgb(229, 229, 229);border-right-color: rgb(229, 229, 229);border-left-color: rgb(229, 229, 229);min-width: 100px;max-width: max(30vw, 320px);"><section style="margin-top: 0px;margin-bottom: 0px;"><span leaf=""><span textstyle="" style="font-size: 15px;">需自行处理安全性细节(如密钥管理)</span></span></section></td></tr></tbody></table>### 7. 示例 JWT  

解码后:  
- **Header**  
:{"alg":"HS256","typ":"JWT"}  

- **Payload**  
:{"sub":"1234567890","name":"John Doe","iat":1516239022}  

二、JWT常见漏洞  
### 1. 算法篡改(Algorithm None Attack)  
- **漏洞原理**  
:  

JWT 头部中的 alg  
 字段指定签名算法,若服务器未严格验证算法类型,攻击者可篡改为 none  
(表示无签名),绕过签名验证。  

- **攻击方式**  
:  

修改 Header 中的 alg  
 为 none  
,删除 Signature 部分,构造未签名的令牌。  

json  

- ```
  • 防御方法

  • 服务器端强制校验 alg
     字段,禁止使用 none
     算法。

  • 使用安全的签名算法(如 HS256
    、RS256
    ),避免接受客户端指定的算法。

2. 弱密钥(Weak Secret Key)

  • 漏洞原理

使用简单密钥(如 secret
、password
)或短密钥进行签名,易被暴力破解或字典攻击。

  • 攻击方式

攻击者通过穷举或已知密钥列表破解密钥,伪造有效签名。

  • 防御方法

  • 使用强密钥(长度 ≥ 32 字节,随机生成)。

  • 定期更换密钥。

  • 对密钥进行安全存储(如密钥管理系统)。

3. 敏感信息泄露(Information Leakage)

  • 漏洞原理

JWT 的 Payload 仅进行 Base64 编码(非加密),若存储敏感数据(如密码、密钥),可被中间人攻击或客户端解码泄露。

  • 攻击示例

json

  • 防御方法

  • 绝不存储敏感信息
    (如密码、密钥)在 Payload 中。

  • 使用 HTTPS 加密传输。

  • 必要时对 Payload 加密(如 JWE)。

4. 签名未验证(Ignored Signature Verification)

  • 漏洞原理

服务器未正确验证 JWT 签名,直接信任 Payload 中的数据。

  • 攻击方式

攻击者篡改 Payload(如将 “role”: “user”
 改为 “role”: “admin”
),服务器未校验签名则接受非法请求。

  • 防御方法

  • 始终验证签名
    ,拒绝无效或未签名的令牌。

  • 使用标准库(如 jsonwebtoken
    )而非自行实现签名验证逻辑。

5. 密钥混淆攻击(Key Confusion Attack)

  • 漏洞原理

当服务端支持多种算法(如 HS256
 和 RS256
)时,攻击者可能将非对称算法(RS256)的公钥作为对称算法(HS256)的密钥进行签名。

  • 攻击方式

  • 假设服务端使用 RS256(私钥签名,公钥验证)。

  • 攻击者将 alg
     改为 HS256,并用公钥作为 HMAC 的密钥生成签名。

  • 服务端误用公钥以 HS256 验证签名,导致通过校验。

  • 防御方法

  • 严格限制支持的算法类型(如仅允许 RS256
    )。

  • 密钥分离:不同算法使用不同密钥。

6. 令牌泄露(Token Leakage)

  • 漏洞原理

JWT 被窃取后,攻击者可利用其进行身份冒充(因服务端无状态,无法主动废止令牌)。

  • 泄露途径

  • XSS 攻击窃取 LocalStorage 中的令牌。

  • 中间人攻击(未使用 HTTPS)。

  • 客户端日志、缓存泄露。

  • 防御方法

  • 使用 HttpOnly
     + Secure
     的 Cookie 存储令牌(防 XSS)。

  • 设置较短的令牌有效期(exp
    )。

  • 结合黑名单机制(如 Redis 记录已注销令牌)。

7. 无效的密钥管理(Poor Key Management)

  • 漏洞原理

密钥硬编码在代码中、使用默认密钥(如 secret
)或密钥轮换策略缺失。

  • 攻击方式

攻击者通过代码泄露、逆向工程获取密钥,伪造任意令牌。

  • 防御方法

  • 密钥存储在安全环境(如环境变量、密钥管理系统)。

  • 禁止使用默认密钥。

  • 定期轮换密钥并兼容旧密钥过渡。

8. 未设置过期时间(Missing Expiration Claim)

  • 漏洞原理

JWT 未设置 exp
(过期时间)或 nbf
(生效时间),导致长期有效。

  • 攻击方式

攻击者窃取令牌后无限期使用。

  • 防御方法

  • 强制设置较短的 exp
    (如 15 分钟)。

  • 结合 Refresh Token 机制续签令牌。

9. 头部注入(Header Injection)

  • 漏洞原理

篡改 JWT 头部参数(如 kid
、jku
、x5u
)指向攻击者控制的密钥或证书。

  • kid 攻击
    :kid
    (Key ID)用于指定密钥,若未校验来源,攻击者可指向恶意密钥。

  • jku 攻击
    :jku
    (JWK Set URL)指定远程公钥地址,攻击者可伪造 URL 提供恶意公钥。

  • 防御方法

  • 校验 kid
     的合法性(如仅允许白名单内的 Key ID)。

  • 禁用动态 jku
     或限制域名(如仅允许可信 URL)。

10. 其他漏洞

  • 空加密算法(Empty Encryption)

某些库可能接受 alg
 为 none
 的加密令牌(如 JWE),需禁用空加密。

  • CSRF 攻击

若通过 Cookie 存储 JWT,需配置 SameSite
 属性防范 CSRF。

  • 令牌压缩问题

部分实现可能因压缩(如 DEFLATE
)导致敏感信息泄露(如 BREACH 攻击),建议禁用压缩。

防御最佳实践

  1. 使用标准库
    (如 jsonwebtoken
    、java-jwt
    ),避免自行实现。

  2. 强制校验算法
    ,禁用 none
     和弱算法。

  3. 限制令牌有效期
    ,结合 Refresh Token。

  4. 密钥管理
    :强密钥、定期轮换、安全存储。

  5. 敏感数据不存储
    在 Payload 中。

  6. 启用 HTTPS
    ,防止中间人攻击。

  7. 安全存储令牌
    :优先使用 HttpOnly
     + Secure
     Cookie。

  8. 审计和监控
    :记录令牌使用情况,检测异常行为。

三、例题

例题1

打开题目提示where is flag?

查看jwt

没有签名部分,只有 jwt 的前两部分 header 和 
payload

[{\”iss\”:\”admin\”,\”iat\”:1747818302,\”exp\”:1747825502,\”nbf\”:1747818302,\”sub\”:\”user\”,\”jti\”:\”9866d74eed9b349d33dbe98c23ae12f3\”}]

iss
: 签发者是admin

  • iat/nbf: 签发时间是1695185318 

  • exp: 过期时间是1695192518

  • sub: 面向用户user

  • jti: 
    JWT
    唯一标识符

把None改成HS256,把user改成admin,重新进行base64编码,访问路径为/admin/,最终获得flag。

这里要注意访问的是/admin/而不是/admin因为访问/admin表示访问admin.php而访问/admin/表示访问的是admin目录下默认的index.php

例题2

某些服务端未校验JWT签名,可以尝试修改payload或者直接删除signature再次请求查看是否有效。

alg字段改为none,sub改为admin,对每一段分别用base64进行加密,然后用.拼接起来,注意最后一个点不能少