心宇

FDF24DCED8C6738F8313A6D3B073C3F4

首页 管理

jwt的工作过程

一个 JWT 通常长这样:

xxxxx.yyyyy.zzzzz

由三个部分组成:

Header.Payload.Signature

中间使用 . 分隔。

  1. Header

Header 描述 JWT 使用什么算法进行签名,以及 Token 类型。

Header 参数 英文全称 中文含义 是否常见 示例
alg Algorithm 签名/加密算法 核心 HS256
typ Type Token 类型 常见 JWT
cty Content Type 内容类型 较少 JWT
kid Key ID 密钥标识符 常见 key-2026-01
jku JWK Set URL JWK Set 地址 较少 https://example.com/jwks.json
jwk JSON Web Key 直接提供公钥 较少 { "kty":"RSA", ... }
x5u X.509 URL X.509 证书地址 较少 https://example.com/cert.pem
x5c X.509 Certificate Chain X.509 证书链 较少 ["MIIC..."]
x5t X.509 Certificate SHA-1 Thumbprint 证书 SHA-1 指纹 较少 abc123...
x5t#S256 X.509 Certificate SHA-256 Thumbprint 证书 SHA-256 指纹 较少 xyz789...
crit Critical 必须处理的扩展字段 较少 ["exp"]
b64 Base64url-Encode Payload 是否对 Payload 做 Base64URL 编码 很少 false

header中的算法

alg 全称 类型 签名方式 密钥
none None 无签名 不签名 无
HS256 HMAC using SHA-256 HMAC HMAC-SHA256 对称 Secret
HS384 HMAC using SHA-384 HMAC HMAC-SHA384 对称 Secret
HS512 HMAC using SHA-512 HMAC HMAC-SHA512 对称 Secret
RS256 RSASSA-PKCS1-v1_5 using SHA-256 RSA RSA + SHA-256 公钥/私钥
RS384 RSASSA-PKCS1-v1_5 using SHA-384 RSA RSA + SHA-384 公钥/私钥
RS512 RSASSA-PKCS1-v1_5 using SHA-512 RSA RSA + SHA-512 公钥/私钥
PS256 RSASSA-PSS using SHA-256 RSA-PSS RSA-PSS + SHA-256 公钥/私钥
PS384 RSASSA-PSS using SHA-384 RSA-PSS RSA-PSS + SHA-384 公钥/私钥
PS512 RSASSA-PSS using SHA-512 RSA-PSS RSA-PSS + SHA-512 公钥/私钥
ES256 ECDSA using P-256 and SHA-256 ECDSA ECDSA + SHA-256 公钥/私钥
ES384 ECDSA using P-384 and SHA-384 ECDSA ECDSA + SHA-384 公钥/私钥
ES512 ECDSA using P-521 and SHA-512 ECDSA ECDSA + SHA-512 公钥/私钥
EdDSA Edwards-curve Digital Signature Algorithm EdDSA Ed25519/Ed448 等 公钥/私钥

HMAC256是对成加密,RSA256是非对称加密,ES256是椭圆曲线非对称密钥

payload/claims

参数 英文全称 中文含义 是否必须 常见用途 示例
iss Issuer 签发者 否 表示 JWT 是谁签发的 "https://auth.example.com"
sub Subject 主题/主体 否 表示 JWT 代表谁,通常是用户 ID "10001"
aud Audience 接收者/受众 否 表示 JWT 是给哪个服务使用的 "api.example.com"
exp Expiration Time 过期时间 否 Token 到什么时候失效 1786500000
nbf Not Before 生效时间 否 在什么时间之前不能使用 1786490000
iat Issued At 签发时间 否 JWT 在什么时候生成 1786490000
jti JWT ID JWT 唯一标识符 否 标识某一个具体 Token,可用于防重放/撤销 "abc123456"

应用自定义 Private Claims

这些不是 JWT 标准固定参数,由后端开发人员自己定义。

参数示例 英文/含义 中文含义 常见用途 示例
userId User ID 用户 ID 标识用户 10001
username Username 用户名 用户名称 "admin"
role Role 角色 权限控制 "admin"
roles Roles 多个角色 多角色权限 ["admin","user"]
permissions Permissions 权限 细粒度权限控制 ["read","write"]
scope Scope 权限范围 OAuth/API 权限 "read write"
email Email 邮箱 用户信息 "a@example.com"
department Department 部门 业务属性 "security"
tenantId Tenant ID 租户 ID 多租户系统 "tenant001"
isAdmin Is Administrator 是否管理员 管理员判断 true

工作过程是:

用户首次登录,会生成jwt token返回给客户的

当客户端再次向服务器发送请求时,会携带token
服务器收到 JWT 后,会使用自己掌握的 Secret 或 Private Key,对“收到的 Header + Payload”重新计算/验证 Signature。并把计算结果和用户携带的token中的签名进行对比,如果相同则证明权限正确.只要 Header 或 Payload 被修改,重新计算出来的签名就与 JWT 携带的原 Signature 不一致,于是 Token 被判定为无效。**

Jwt攻击面分析

                         JWT
                          │
        ┌─────────────────┼─────────────────┐
        │                 │                 │
      Header            Payload          Signature
        │                 │                 │
        │                 │                 │
    alg / kid          Claims            HS/RS/ES
    jku / jwk          exp              Secret/Key
        │              iss/aud
        │              sub
        │              role
        │                 │
        ▼                 ▼                 ▼
   算法攻击          Claims攻击          签名攻击
        │                 │                 │
        └─────────────────┼─────────────────┘
                          │
                          ▼
                     JWT验证逻辑
                          │
                          ▼
                     业务授权逻辑
                          │
                          ▼
                     权限绕过 / 提权

===================================================================================================================================================================================================================



JWT 攻击面
│
├── ① 算法攻击
│   ├── alg 混淆
│   ├── none
│   └── HS256 / RS256 混淆
│
├── ② 密钥攻击
│   ├── HS256 弱 Secret
│   ├── Secret 泄露
│   ├── Private Key 泄露
│   ├── kid
│   ├── jwk
│   ├── jku
│   └── JWKS / Key Rotation
│
├── ③ Claims 攻击
│   ├── exp
│   ├── nbf
│   ├── iss
│   ├── aud
│   ├── jti
│   └── 自定义 Claims
│
├── ④ Token 攻击
│   ├── Replay
│   ├── JWT 泄露
│   └── XSS
│
└── ⑤ 业务/实现攻击
    ├── 权限逻辑
    ├── Claims 信任
    ├── Parser 差异
    └── 自定义验证

攻击总结表

类型 核心问题 如何实现攻击 / 基本思路 典型后果
alg 混淆 服务器没有严格限制算法 修改 Header 中的 alg,尝试让服务端使用与原 Token 不同的算法进行验证;重点检查服务端是否根据客户端提供的 alg 动态选择验证方式 伪造 Token
none 服务器错误接受无签名 Token 将 Header 的 alg 改为 none,移除 Signature;如果服务端仍接受,则无需密钥即可构造 Token 伪造 Token、认证绕过
HS256 弱密钥 HMAC Secret 强度不足 获取一个合法 HS256 JWT 后,对 Secret 进行离线字典/暴力猜测;找到 Secret 后即可重新计算合法 Signature 任意伪造 Token
HS/RS 混淆 对称/非对称算法处理错误 原 Token 使用 RS256 时,尝试将 alg 改成 HS256;如果服务端错误地把 RSA Public Key 当 HMAC Secret 使用,就可能利用该 Public Key 生成伪造签名 任意伪造 Token
kid Key ID 使用方式不安全 修改 kid,观察服务器如何根据它寻找 Key;如果 kid 被拼接到文件路径、SQL 查询等位置,则进一步检查路径遍历、SQL 注入等问题 Key 操纵、注入、认证绕过
jwk 信任 JWT 自带公钥 在 Header 中提供攻击者自己的 JWK,并用对应 Private Key 签名;如果服务端直接信任 Header 中的 JWK,则可能接受伪造 Token 伪造 Token
jku 信任任意 JWKS URL 修改 jku 指向攻击者控制的 JWKS;如果服务器会从任意 URL 获取公钥,则可让服务器使用攻击者的 Public Key 验证 Token 伪造 Token
JWKS Key 管理/选择错误 检查 JWKS 中的 kid、算法、Key 类型及旧 Key;测试服务端是否接受错误 Key、过期 Key 或跨服务 Key 伪造 Token、旧 Token 持续有效
exp 未检查过期时间 使用已经超过 exp 的 JWT 请求 API;如果仍被接受,说明过期验证存在问题 Token 长期有效
nbf 未检查生效时间 构造/使用 nbf 位于未来的 Token;如果服务器立即接受,则说明没有正确检查 nbf 提前使用 Token
iss 未验证签发者 使用另一个可信系统签发的 JWT,或者修改 iss;测试目标服务是否接受非预期 Issuer 跨系统 Token 滥用
aud 未验证接收者 获取针对 Service A 的合法 Token,然后尝试访问 Service B;如果 B 不验证 aud,可能接受 A 的 Token 跨服务认证绕过
Replay Token 本身可以重复使用 获取一个合法 Token 后,在不同请求、设备或时间重复使用;如果系统没有撤销/重放控制,则可持续冒用身份 账号冒用
JWT 泄露 Bearer Token 被窃取 从浏览器、日志、URL、代理记录、源码、前端存储等位置发现 JWT,然后直接携带该 Token 请求 API 账号接管
XSS JWT 存储位置容易被 JS 读取 如果 Token 存在 localStorage 等 JS 可访问位置,存在 XSS 时可读取 Token 并发送到攻击者控制的位置 Token 窃取、账号接管
Secret 泄露 HS256 Secret 暴露 从源码、.env、配置文件、Git、CI/CD、容器环境变量等位置寻找 JWT Secret;获得后自行签名 Token 任意伪造 Token
Private Key 泄露 RS256 Private Key 暴露 从服务器、备份、配置、CI/CD 等位置获得 RSA Private Key,然后使用该私钥生成合法 JWT 任意伪造 Token
权限逻辑 Authentication ≠ Authorization 获得合法普通用户 Token 后,修改/测试 role、permissions、scope 等 Claims,并观察后端是否真正执行权限检查 越权、权限提升
Parser 差异 不同组件解析 JWT 的方式不同 构造边界/异常 Token,让 API Gateway、WAF、JWT 库和后端对同一个 Token 得出不同解析结果 验证绕过
Key Rotation 旧 Key 未及时撤销 获取旧 Key 或旧 Token 后,在密钥轮换之后继续使用;如果服务端仍接受旧 Key/Token,则可以持续使用 持续伪造/长期冒用
Claims 信任 过度信任 Payload 修改 userId、role、tenantId、permissions 等 Claims;如果签名验证、身份查询或授权逻辑设计不当,则可能控制身份/权限 越权、IDOR、提权
自定义验证 开发者自行实现验证逻辑错误 分析 Token 验证代码,寻找“只解析不验签”“异常时默认通过”“算法未限制”“Claims 验证缺失”等逻辑错误 认证绕过

1、JWT 签名与业务数据不一致

例如 Payload:

{
    "userId": 1001,
    "role": "user"
}

Signature 完全正确。

但后端真正查询数据库:

userId = 1001

得到:

role = admin

于是出现:

JWT role
    ↓
user

Database role
    ↓
admin

如果不同模块使用不同来源的权限信息,就可能产生:

Identity / Authorization Inconsistency

这种问题严格来说不一定是 JWT 漏洞,但在 JWT 渗透测试里非常重要。

2、alg 算法混淆

这是 JWT 最经典的攻击面之一。

例如服务器正常使用:

{
    "alg": "RS256"
}

攻击者尝试让服务器按照另一种算法处理。

典型历史问题是:

RS256
  ↓
RSA 非对称签名

HS256
  ↓
HMAC 对称签名

如果服务端错误地把 RSA 公钥当成 HMAC Secret 使用,就可能出现:

原本:

Private Key → RS256 → Signature
Public Key  → Verify


错误情况:

Public Key → HS256 → Signature
                ↓
           服务器错误接受

这就是经典的:

Algorithm Confusion / RS256 → HS256

现在成熟 JWT 库通常已经对此有防护,但老旧库、自定义实现仍值得检查。


3、alg: none

JWT 标准存在 none 算法,表示:

没有数字签名

理论上:

Header.Payload.

就是一个合法的 JWS 形式。

历史上一些 JWT 实现错误地:

接受客户端指定的 alg
        ↓
发现 alg = none
        ↓
跳过 Signature 验证
        ↓
直接信任 Payload

攻击者于是可能修改:

{
    "role": "user"
}

为:

{
    "role": "admin"
}

现代成熟框架通常默认禁止这种情况。

所以今天测试时,不应该看到 none 就认为一定存在漏洞,而应该验证:

服务器是否真的接受 none

4、弱密钥 / Secret 爆破

这是 HS256 特别值得关注的问题。

例如:

HS256

实际上是:

HMAC-SHA256(
    Header.Payload,
    Secret
)

如果 Secret 是:

123456
secret
admin
password
jwtsecret
company2024

攻击者可以进行离线猜测。

重点在于:

不需要不断请求服务器。

攻击者拿到 JWT 后,可以本地验证候选 Secret。

例如逻辑上:

JWT
 │
 ├── Header
 ├── Payload
 └── Signature
          │
          ▼
     猜测 Secret
          │
          ▼
   重新计算 HMAC
          │
          ▼
 Signature 是否一致?

如果一致:

Secret 找到了

然后理论上就可以重新签发任意 Payload。

所以:

HS256 + 弱 Secret

是非常经典的 JWT 风险组合。


5、HS256/RS256密钥类型混淆

这个和单纯的 alg 攻击相关,但值得单独理解。

HS256

        Secret
       /      \
      /        \
签名服务器    验证服务器

签名和验证使用同一个 Secret。


RS256

Private Key
    │
    ▼
  签名

Public Key
    │
    ▼
  验证

因此:

HS256 → 对称算法
RS256 → 非对称算法

如果应用没有严格限制:

允许的算法
允许的密钥类型
允许的 Key ID

就可能出现算法混淆问题。


6、kid 攻击

kid:

Key ID

例如:

{
    "alg": "RS256",
    "kid": "key-2026-01"
}

服务器可能根据:

kid

选择对应的公钥:

kid = key-2026-01
        ↓
找到对应 Public Key
        ↓
验证 Signature

问题在于:

如果开发人员把 kid 当成普通字符串直接参与文件、数据库、命令或其他操作,就可能产生注入类漏洞。

例如概念上:

kid
 ↓
文件路径
 ↓
读取 Key

如果实现不安全,就可能产生:

Path Traversal

或者:

SQL Injection

等问题。

因此:

kid

本身不是漏洞。

漏洞来自:

服务器如何使用 kid。


7、jku 攻击

jku:

JSON Web Key Set URL

JWT Header 可能出现:

{
    "alg": "RS256",
    "jku": "https://example.com/.well-known/jwks.json"
}

服务器可能:

读取 jku
   ↓
下载 JWKS
   ↓
找到对应 kid
   ↓
使用公钥验证 JWT

危险点是:

如果服务器完全信任客户端提供的 jku,攻击者可能尝试让服务器加载攻击者控制的公钥。

逻辑:

攻击者
  │
  │ JWT
  │ jku = 攻击者控制的 JWKS
  ▼
服务器
  │
  │ 下载 JWKS
  ▼
攻击者公钥
  │
  ▼
服务器使用该公钥验证

于是攻击者可以:

自己的 Private Key
       ↓
签名 JWT
       ↓
服务器拿攻击者 Public Key 验证
       ↓
验证成功

所以安全实现通常应该:

允许的 JWKS 地址 = 白名单

而不是:

任意 jku = 任意 URL

8、jwk 直接提供公钥

类似的问题还有:

{
    "alg": "RS256",
    "jwk": {
        "kty": "RSA",
        ...
    }
}

如果服务器直接信任 Header 中提供的 JWK:

JWT Header
   │
   ▼
jwk = 攻击者公钥
   │
   ▼
服务器拿它验证

就会导致:

自己生成密钥
        ↓
自己签 JWT
        ↓
把自己的公钥塞进 JWT
        ↓
服务器用自己的公钥验证

因此:

验证密钥必须来自可信来源,而不能由待验证的 JWT 自己决定。


9、JWK / JWKS 配置错误

JWKS:

JSON Web Key Set

例如:

/.well-known/jwks.json

里面可能有:

{
    "keys": [
        {
            "kty": "RSA",
            "kid": "key1",
            "use": "sig"
        }
    ]
}

常见安全问题包括:

kid 管理错误
旧密钥没有撤销
错误的 key 用途
算法与 key 类型不匹配
JWKS 来源不可信
缓存更新问题
多租户之间 Key 混用

10、Payload / Claims 篡改

这是最直观的一类。

例如:

{
    "sub": "1001",
    "role": "user"
}

攻击者尝试:

{
    "sub": "1001",
    "role": "admin"
}

如果服务器:

没有验证 Signature

或者:

Signature 验证存在逻辑漏洞

就可能直接导致:

普通用户 → 管理员

11、JWT 权限绕过

这是实际项目里非常重要的一类。

即使 JWT 签名完全正确:

Signature ✓

也不代表:

Authorization ✓

例如:

{
    "sub": "1001",
    "role": "user"
}

服务器正确验证了 JWT。

但是 API:

GET /api/admin/users

只检查:

Token 是否有效

却没有检查:

role == admin

那么:

认证成功 ≠ 授权成功

这属于:

Authentication / Authorization 混淆

也是 JWT 项目里非常常见的问题。


12、exp 过期时间验证问题

JWT:

{
    "sub": "1001",
    "exp": 1754993600
}

如果服务器没有正确检查:

exp

那么 Token 可能永久有效。

风险:

JWT 泄露
   ↓
攻击者长期使用

另外还有:

nbf
iat
iss
aud

等 Claims 的验证问题。


13、aud / iss 验证缺失

例如一个 JWT 是给:

Service A

签发的。

但:

Service B

也接受同一个 JWT。

如果 B 应该只接受:

{
    "aud": "service-B"
}

但它完全不检查 aud:

Service A Token
      ↓
Service B
      ↓
接受

就可能产生:

Cross-Service Token Abuse

在微服务环境尤其值得关注。


14、JWT 重放攻击 Replay

JWT 是 Bearer Token:

谁拿到
谁就可以使用

例如:

用户
 ↓
JWT
 ↓
攻击者窃取

攻击者无需知道:

用户名
密码

直接:

Authorization: Bearer <stolen-JWT>

即可使用。

如果 Token:

有效期很长
没有撤销机制
没有绑定客户端
没有 jti 防重放

风险会更大。


15、JWT 泄露

JWT 本身可能没有密码,但它相当于:

身份证 + 通行证

常见泄露位置:

LocalStorage
SessionStorage
Cookie
URL
Referer
日志
浏览器插件
前端错误日志
代理日志
聊天记录
Git 仓库
前端源码

尤其不要把 JWT 放到 URL:

https://example.com/api?token=xxxxx

因为 URL 很容易进入:

Browser History
Proxy Logs
Web Server Logs
Referer

16、XSS + JWT

如果 JWT 放:

localStorage

那么:

XSS
 ↓
JavaScript
 ↓
读取 localStorage
 ↓
JWT 被窃取

于是:

XSS
 +
JWT

可能直接变成:

账号接管

这也是为什么很多安全架构会考虑:

HttpOnly Cookie

不过 Cookie 又需要考虑:

CSRF
SameSite
Secure

所以并不是简单地说:

Cookie 永远比 localStorage 安全

17、签名验证逻辑错误

这是自定义 JWT 实现特别危险的一类。

例如开发人员自己写:

verify(token)

可能出现:

只解析 Payload
没有验证 Signature

验证 Signature 后没有检查 exp

检查 Signature 的算法与 Header 不一致

错误处理导致验证失败后继续执行

异常情况下默认 Token 有效

这类问题往往比某一个具体 JWT 算法漏洞更加现实。


18、时间验证问题

例如:

exp
nbf
iat

涉及 Unix Timestamp:

exp = 1754993600

如果不同服务器:

时钟不同步

或者应用:

时间单位搞错
秒 / 毫秒

可能造成:

Token 提前失效
Token 永久有效
Token 尚未生效却被接受

19、JWT 密钥泄露

这其实是非常严重但经常被忽视的一类。

例如:

.env
config.yaml
application.properties
Docker Compose
GitHub
GitLab
CI/CD
容器环境变量
源码
备份文件
日志

出现:

JWT_SECRET=xxxx

那么:

JWT Secret 泄露
      ↓
攻击者可以自行签名
      ↓
伪造 JWT

对于 HS256:

Secret 泄露
   ↓
几乎等于可以伪造 Token

对于 RS256:

Private Key 泄露
   ↓
攻击者可以伪造 Token

而:

Public Key 泄露

通常不是漏洞,因为 RS256 的设计本来就是允许公开 Public Key。


20、密钥轮换 / kid 管理问题

大型系统通常不会永远使用:

同一个 Secret

而会:

key1
key2
key3
...

通过:

kid

标识。

如果旧 Key:

已经泄露

但是服务器:

仍然接受旧 kid

那么攻击者可能继续伪造 Token。

所以 JWT Key Management 本身也是一个攻击面。


21、嵌套 JWT/JWT Parser 差异

比较高级的一类问题是:

不同 JWT 库
不同语言
不同组件

对于 Token 的解析规则可能不完全一致。

例如:

API Gateway
     ↓
JWT Parser A
     ↓
认为 Token 有效
     ↓
后端
     ↓
JWT Parser B
     ↓
按照不同规则解释

这类问题属于:

Parser Differential / Parsing Confusion

在复杂微服务系统中尤其值得注意。

posted on 2026-09-30 10:19  心宇16969  阅读(14)  评论(0)    收藏  举报