关于 Web 安全:5. 认证绕过与权限控制分析
一、无验证码爆破登录
无验证码爆破登录指的是系统登录接口没有设置验证码、图形验证、滑动验证或行为校验,导致攻击者可以通过自动化脚本进行用户名 + 密码组合的穷举猜解(暴力破解),从而登录系统。
1.1 攻击原理与流程
原理:
-
系统允许无限制登录尝试
-
没有验证码、限速、锁定等防爆破机制
-
响应可识别成功/失败(通过响应内容、状态码等)
攻击流程:
-
发现目标登录接口(GET 或 POST)
-
构造用户名和密码字典(如:
admin:123456
) -
使用脚本或工具暴力提交登录请求
-
根据响应识别是否登录成功
-
登录成功后获取会话或敏感信息
1.2 真实案例分析
示例接口:
POST /api/user/login
Content-Type: application/json{"username": "admin","password": "admin123"
}
成功识别方式:
-
响应内容包含
login success
、token
、200 OK
-
失败响应为
用户名或密码错误
或401 Unauthorized
-
登录成功后返回
Set-Cookie: sessionid=xxx
1.3 工具使用演示
1)Burp Suite Intruder 模拟爆破
步骤:
-
抓取登录请求并发送到 Intruder
-
设置 payload 位置(如用户名/密码字段)
-
使用弱密码字典(如:
rockyou.txt
) -
设置线程并运行攻击
-
根据响应长度、状态码、内容分析是否登录成功
2)Python 脚本爆破
import requestsurl = 'http://target.com/api/login'
username = 'admin'
passwords = ['123456', 'admin123', 'password', '1234']for pwd in passwords:data = {"username": username, "password": pwd}r = requests.post(url, json=data)if "token" in r.text or r.status_code == 200:print(f"[+] 成功登录: {username}:{pwd}")break
1.4 绕过技巧(高级技巧)
1)延迟绕过
如果系统有一点点延迟限制,可在脚本中加入 time.sleep(1)
绕过节流。
2)User-Agent 随机
防止被 WAF 拦截。
import random
headers = {'User-Agent': random.choice(ua_list)}
3)多 IP(使用代理池)
可绕过 IP 黑名单。
proxies = {'http': 'http://1.1.1.1:8080'}
r = requests.post(url, json=data, proxies=proxies)
4)多线程异步爆破
使用 aiohttp
、gevent
提高速度。
1.5 真实场景爆破目标(仅限合法授权环境)
可用于练习的靶场:
靶场 | 描述 |
---|---|
DVWA | 有低安全级别模式可测试暴力破解 |
bWAPP | 包含 Login Brute Force 模块 |
WebGoat | OWASP 官方靶场,内含暴力破解关卡 |
自建接口 | 用 Flask/Django 模拟登录接口 |
1.6 防御与修复建议
1)加入验证码机制
-
图形验证码(如:4位字母)
-
行为验证(如极验滑块、滑动)
-
无感验证码(如 Google reCAPTCHA v3)
2)登录失败限制
-
一定时间内失败超过 5 次锁定账号或 IP
-
登录失败时响应延迟(如:sleep 2秒)
3)异常检测与告警
-
检测单 IP 多次登录失败
-
异常登录行为告警(频繁尝试/UA 变化/IP 变化)
4)接口风控策略
-
绑定设备指纹、地理位置
-
登录操作接入风控系统打分判断是否可信
1.7 小结表格
项目 | 描述 |
---|---|
风险等级 | 高(可导致账号被爆破登录) |
攻击者目标 | 弱口令、默认口令、已泄露密码 |
关键判断 | 是否有验证码、是否有限速、是否有响应差异 |
推荐工具 | Burp Suite、Hydra、Python 脚本 |
防御措施 | 验证码、限流、锁定、风控判断 |
1.8 实战建议
-
在做 Web 渗透时,首先尝试是否存在无验证码登录
-
常见弱口令组合(admin/admin,test/123456)
-
SRC 挖洞时该类问题危害程度高,提交价值大
二、验证码绕过
验证码绕过指的是攻击者绕过网站或应用的验证码验证机制,从而继续暴力破解、注册、刷票、登录等操作。它是认证绕过中非常常见的一种方式,且经常出现在中低分段 SRC 中。
2.1 验证码的种类
了解不同形式,才能针对性绕过
验证码类型 | 描述 | 绕过难度 |
---|---|---|
普通图形验证码 | 数字/字母/混合 | 低 |
点选验证码 | 点击图中指定位置 | 中 |
滑动验证码(极验) | 拖动滑块到缺口位置 | 高 |
行为验证码(reCAPTCHA) | 综合行为检测 | 非常高 |
自定义前端验证 | 前端逻辑控制,无后端校验 | 极易绕过 |
2.2 验证码绕过的常见方式
1)验证码接口不校验 / 前端校验(最常见)
-
后端没有校验验证码,仅在前端判断
-
提交的请求中即便验证码为空也能登录成功
实战方法:
-
Burp 抓包→删除验证码字段→重放请求
2)验证码可重用 / 不变更
-
获取一次验证码后,可多次使用(接口未绑定 session)
-
或者验证码永远是“1234”这种默认值
实战方法:
1. 访问验证码接口 /captcha.jpg
2. 保留验证码不刷新,多次尝试登录
3)验证码校验与登录接口解耦
-
验证码验证接口是独立的,登录接口不验证验证码值
-
可直接构造登录接口请求,不调用验证码接口
实战方法:
1. 访问 /checkCaptcha?code=xxx
2. 验证通过后尝试在 login 请求中不传验证码字段或传任意值
4)验证码识别(OCR破解)
-
使用 OCR 工具(如 Tesseract)识别图形验证码内容
-
可用于自动化暴力破解
示例代码:
from PIL import Image
import pytesseractimg = Image.open("captcha.jpg")
text = pytesseract.image_to_string(img)
print(f"识别验证码为: {text}")
5)极验 / 行为验证码绕过
极验滑动验证码 w
参数是加密的,但存在以下绕过可能:
-
伪造行为数据绕过(模拟正常轨迹)
-
使用无感验证接口
-
客户端注册成功后复制
lot_number
、payload
、w
等参数复用 -
调用极验第三方打码平台
示例:
接口:
GET /validate?lot_number=xxx&payload=xxx&captcha_id=xxx&w=加密参数方式:
- hook 极验 js 生成的参数
- 或在 App 中 hook geetest sdk 提交行为参数
2.3 验证码绕过的实战案例
案例 1:验证码仅前端校验
if (input_code === real_code) {// 允许提交
}
解法:用 Burp 抓包 → 删除验证码字段 → 直接发送 → 登录成功
案例 2:验证码可预测
验证码图片是 /captcha/1234.png
,每次验证码就是文件名。
解法:直接拼接文件名获取验证码,不需要识别
案例 3:极验绕过
使用 Frida hook gt3tool.js
→ 拿到 w
参数 → 模拟拖动验证成功 → 登录接口验证通过
解法:
1. Hook geetest JS 函数
2. 模拟轨迹生成行为数据
3. 伪造 w 参数
2.4 验证码识别自动化实战(图形验证码)
用 Python 实现自动识别并提交验证码:
import requests
from PIL import Image
import pytesseract# 获取验证码图片
r = requests.get("http://xxx.com/captcha")
with open("code.jpg", "wb") as f:f.write(r.content)# 识别验证码
code = pytesseract.image_to_string(Image.open("code.jpg")).strip()# 登录请求
data = {"username": "admin", "password": "123456", "captcha": code}
r = requests.post("http://xxx.com/login", data=data)print("登录结果:", r.text)
2.5 防御与修复建议
防御点 | 描述 |
---|---|
后端必须验证验证码 | 不能仅在前端验证 |
验证码与 session 绑定 | 每次验证码只对应一次尝试 |
加入时间戳、Token校验 | 防止验证码重放 |
限制验证码使用次数 | 每个验证码只能用一次 |
接入行为验证码 | 如极验、阿里滑动验证码 |
拦截异常行为 | 单 IP 多次失败尝试触发封禁或验证码加强 |
2.6 小结表格
绕过方式 | 难度 | 特点 |
---|---|---|
前端验证 | ★ | 简单抓包可绕过 |
验证码可复用 | ★★ | 无绑定或接口设计缺陷 |
OCR识别 | ★★★ | 需要识别图片内容 |
极验行为绕过 | ★★★★ | 需要 hook/逆向分析 |
打码平台识别 | ★★★ | 依赖打码服务 |
2.7 练手靶场 / 练习平台
靶场 | 特点 |
---|---|
DVWA | 图形验证码绕过 |
bWAPP | 登录验证码模块 |
自建 Flask 验证码系统 | 可手动实现各种验证码类型 |
极验测试站 | 模拟行为验证 |
三、忘记密码功能缺陷
忘记密码功能(通常为 找回密码
或 重置密码
)是用户身份恢复的一种手段。若这个流程的认证与校验不严,攻击者可借机:
-
未授权重置他人密码
-
暴力破解验证码 / Token
-
伪造请求篡改验证信息
-
信息泄露(邮箱/手机)
-
造成账户接管
3.1 常见的风险点类型(分门别类)
风险点类型 | 风险点描述 |
---|---|
验证码可爆破 | 手机/邮箱验证码无限尝试 |
验证码未绑定用户 | 用验证码重置任意账号密码 |
找回链接未过期 | 验证链接可长期使用 |
Token 可预测 | 使用递增值或 Base64 编码 |
缺少身份校验 | 直接可修改他人密码 |
中间信息泄露 | 接口返回用户手机号、邮箱等敏感信息 |
任意用户密码重置 | 逻辑设计错误,导致可以重置任意账号密码 |
3.2 攻击原理与流程分析
常见找回流程如下:
-
用户输入用户名/邮箱/手机号
-
服务器生成验证码(短信/邮箱/图形)
-
验证码验证成功后跳转到重置页面
-
用户输入新密码 → 提交 → 修改密码成功
攻击者的目标:
利用流程设计缺陷,绕过身份校验、控制任意账号密码
3.3 风险点案例与演示
案例 1:验证码无限尝试(爆破)
POST /api/verify-code
{"username": "admin","code": "123456"
}
系统不限制验证码尝试次数,可用脚本从 000000~999999 爆破。
Python 示例:
for i in range(1000000):code = str(i).zfill(6)data = {"username": "admin", "code": code}r = requests.post(url, json=data)if "验证成功" in r.text:print(f"[+] 找到验证码: {code}")break
案例 2:验证码未绑定用户
-
请求验证码时输入手机号 A(攻击者手机号)
-
请求重置密码时填写用户名 B(受害人)
如果系统不验证手机号与用户名是否匹配,就会导致:
可用自己的验证码重置他人密码。
案例 3:重置链接未过期 / 可重放
GET /reset-password?token=eyJ1c2VyIjoiYWRtaW4ifQ==
-
Token 没有过期机制
-
Token 可反解或枚举
-
可以重复使用
风险点方式:
-
解码 token → 修改 user 字段
-
请求链接 → 重置任意账号密码
案例 4:缺少身份认证
在某些系统中:
POST /reset
{"username": "admin","new_password": "123456"
}
无需验证码或令牌,直接通过用户名修改密码 → 重大风险点。
3.4 验证码/Token 风险点实战小结
类型 | 风险点点 |
---|---|
验证码爆破 | 无次数限制、无封锁机制 |
Token 弱加密 | Base64 明文、简单加密、可预测 |
会话未绑定用户 | 使用任意验证码验证任意账号 |
验证码通用 | 多人共用验证码 |
找回链接不失效 | 可反复使用、不限时间 |
逻辑不严谨 | 用户与验证码不强绑定 |
3.5 防御与修复建议
安全控制点 | 建议 |
---|---|
验证码限制尝试次数 | 3~5 次错误锁定、加入滑动验证码 |
验证码必须绑定用户 | 手机号、邮箱与用户名匹配 |
Token 加密复杂化 | 使用 JWT / 随机 UUID + 签名 |
Token 设置过期时间 | 例如 5 分钟内有效 |
验证码与 IP / 会话绑定 | 一人一码、一人一链接 |
重置后自动失效旧 Token | 防止重放 |
重置流程需完整身份验证 | 防止跳过验证直接改密码 |
3.6 实战靶场建议练习
靶场 | 特点 |
---|---|
DVWA / bWAPP | 有验证码模块、密码重置模块 |
自建 Flask/Django 找回密码接口 | 模拟 token 验证流程 |
风险点练习平台 VulApps | 可练习任意密码重置、验证码逻辑缺陷 |
3.7 SRC 挖洞建议
-
寻找 未绑定用户的验证码接口
-
检查验证码可否多次尝试(尤其是短信/邮箱验证码)
-
验证是否可用某人手机号重置另一个人账号密码
-
检查 Token 是否可预测、可重放、未加签
-
验证是否有 IDOR 问题(越权修改密码)
3.8 小结
“忘记密码功能缺陷” 属于高危认证绕过类风险点,一旦发现可能导致:
-
任意账号接管
-
用户信息泄露
-
核心系统控制权被获取
四、OAuth 滥用
OAuth 是一种授权协议,常用于:
-
第三方登录(微信登录、QQ登录、GitHub登录)
-
第三方授权访问(授权某 APP 访问你的资源)
例如:“使用微信登录本网站”,就是 OAuth 授权流程的典型例子。
4.1 OAuth 认证基本流程(理解核心机制)
OAuth 授权流程简化如下:
[用户] → 请求授权 → [授权服务器] → 返回 code → 用 code 换 token → 获取用户信息
详细步骤如下:
-
用户访问客户端 A,点击“用平台 X 登录”
-
重定向到平台 X 的授权页面,用户点击授权
-
平台 X 返回一个临时 code 给客户端 A
-
客户端 A 拿 code 向平台 X 换取 access_token
-
拿 access_token 获取用户信息(openid 等)
-
客户端用 openid 绑定本地账号,实现登录
4.2 OAuth 滥用常见风险点类型
风险点类型 | 描述 |
---|---|
openid 可伪造 / 不校验 | 本地系统不校验 access_token,直接用 openid 登录 |
access_token 不验证归属 | 使用别人的 access_token 登录任意账号 |
缺少绑定校验 | 无需绑定用户,任意授权直接创建本地账号 |
回调地址未限制 | 重定向地址可被篡改,导致 token 泄露 |
授权码重用 | code 被重用,导致 token 被盗 |
IDOR 结合 OAuth | 利用 openid 构造 IDOR 攻击,越权获取其他账号信息 |
4.3 核心风险点原理分析
风险点1:只用 openid 登录,未验证 access_token
# 后端伪代码
openid = request.GET.get("openid")
user = db.query("select * from users where openid=?", openid)
login(user) # 无验证,直接登录
攻击方式:
-
构造任意 openid 值(如 admin 的 openid)发送请求,即可伪造身份。
风险点2:access_token 无归属校验
某些系统只验证 access_token 的合法性,不判断是否属于当前用户。
攻击方式:
-
A 用户获取自己的 access_token,登录后抓包
-
替换请求参数中的 openid 为 B 用户的 openid
-
登录系统,成功冒充 B 用户
风险点3:回调地址未限制(Redirect URI 绕过)
授权平台返回 code
时,是重定向到开发者系统的 redirect_uri。
攻击方式:
-
攻击者将 redirect_uri 改为自己的服务器,获取 code 或 token,从而劫持授权流程
风险点4:授权码重用(code 重放)
授权码(code)理论上只可用一次,有些服务未做限制。
攻击方式:
-
抓包保存 code
-
多次调用 token 接口获取不同 token,造成滥用
4.4 实战案例演示
案例:某平台 GitHub 登录风险点(真实报告)
-
请求参数中包含
access_token
和openid
-
后端只验证 openid 是否存在本地数据库,未校验 token
攻击步骤:
1. 注册自己的 GitHub 账号,获取 access_token 和 openid
2. 抓包登录请求
3. 替换 openid 为目标用户(B)的 openid
4. 提交请求 → 成功登录 B 的账号
案例:redirect_uri 未校验
某 OAuth 授权页面:
https://auth.xxx.com/oauth?client_id=abc&redirect_uri=https://evil.com/code
平台没有限制 redirect_uri 白名单,攻击者可收集 code 进行 token 获取,控制账号。
4.5 防御与修复建议
防御点 | 描述 |
---|---|
强制校验 access_token | 通过授权平台接口校验是否有效 |
access_token 与 openid 绑定 | 校验是否为当前 openid 所属 |
code 只能使用一次 | 实现短期有效 + 一次性消耗 |
redirect_uri 白名单验证 | 严格限制授权回调地址 |
授权绑定需人工确认 | 第一次使用第三方登录应要求绑定本地账号 |
日志审计 | 授权失败/重复使用需告警 |
4.6 测试 OAuth 风险点常用点
-
是否能更换 openid 登录其他人
-
是否能复用自己的 access_token,配合他人 openid 登录
-
是否能通过构造 code 或 redirect_uri 实现跳转劫持
-
是否能跳过绑定步骤直接创建本地账户
-
是否能将一个第三方账号绑定多个本地用户
4.7 OAuth 风险点测试技巧
-
抓取登录流程,关注
access_token
,openid
,code
-
使用 Burp 修改 openid,尝试越权
-
用别人的 openid + 自己的 token 组合测试
-
多次使用 code,看是否存在重放
-
尝试设置 redirect_uri 为恶意服务器,是否能劫持授权
4.8 可练习平台 / 靶场推荐
平台 | 特点 |
---|---|
DVWA + GitHub 登录 | 自建测试 OAuth 认证 |
真实 OAuth 授权接入的业务系统 | 如第三方登录、微信公众号登录 |
VulApps / WebGoat | 有 OAuth 实战模块 |
GitHub Pages 结合 Flask 模拟 OAuth 接入 | 可调试回调地址与认证流程 |
4.9 小结
OAuth 是授权协议不是认证协议,滥用 OAuth 造成的风险点普遍存在于绑定逻辑和 token 校验环节,在实际测试中:
-
重视 openid 与 access_token 的绑定
-
检查每一步逻辑是否校验充分
-
回调地址必须受控
-
所有外部参数都需要后端安全验证
五、JWT 篡改
JWT(JSON Web Token)是一种用于身份验证的令牌格式,结构如下:
header.payload.signature
三部分用 .
分隔:
-
header
:声明类型(typ)和算法(alg) -
payload
:有效载荷(如用户名、权限) -
signature
:签名,用于防篡改
5.1 JWT 篡改的基本原理
JWT 是前端存储身份的载体,若签名机制或验证方式存在问题,攻击者就可能:
-
篡改用户身份(将自己变成管理员)
-
绕过登录认证
-
控制访问权限
5.2 JWT 篡改常见风险点类型
风险点类型 | 描述 |
---|---|
alg:none 绕过 | 将签名算法改为 none,签名被跳过 |
弱密钥爆破 | 使用弱密钥(如 123456 ),可伪造签名 |
公钥当私钥用 | 后端误用公钥验证签名,导致伪造 |
未验证签名 | 后端只解析 payload,不验证 signature |
风险点算法替换 | 将 HS256 换成 RS256 或反过来造成验证失效 |
信息泄露 | JWT 可解码,泄露用户信息/敏感字段 |
5.3 JWT 解码与伪造示例
JWT 示例:
eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ1c2VyIjogImFkbWluIn0.WB1K8s...
解码:
# 解码 Header 和 Payload
echo 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9' | base64 -d
echo 'eyJ1c2VyIjogImFkbWluIn0' | base64 -d
如果签名弱,攻击者可构造:
{"alg": "HS256","typ": "JWT"
}
{"user": "admin"
}
# 用爆破出的 key 签名 payload 伪造 token
5.4 详细风险点分析
1)alg: none 绕过
签名算法改为 none
,服务器不校验签名
原始 token:
{"alg": "HS256","typ": "JWT"
}
修改为:
{"alg": "none","typ": "JWT"
}
然后伪造 payload:
{"user": "admin","role": "admin"
}
组合为:
base64(header).base64(payload).
末尾没有签名,若后端未禁止 none
算法,则可直接伪造登录!
2)弱密钥爆破
如果服务器使用弱 key,如:
key = "123456"
jwt.encode(payload, key, algorithm="HS256")
攻击者可使用字典爆破 key:
工具:jwt_tool.py
、jwt-cracker.py
python3 jwt_tool.py -t <token> -d rockyou.txt
爆破成功后,可伪造任意 payload,构造伪造身份的 token。
3)公钥当私钥使用(RS256 到 HS256 攻击)
服务端使用非对称加密(RS256),但误用为对称加密验证。
攻击者构造:
-
将 alg 改为
HS256
-
用公钥作为对称密钥签名 payload
如果服务端用公钥验证,则会错误地通过签名验证。
4)签名未校验
部分服务端只取 payload 不验签,例如:
data = jwt.decode(token, verify=False)
user = data['user']
攻击者直接 base64 修改 payload 内容并发送,无需签名校验,即可绕过权限验证。
5.5 实战案例演示
案例 1:某系统 JWT 中 alg 可改为 none
原始 token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QifQ.[签名]修改为:
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4ifQ.
提交后成功绕过,登录 admin 账号。
案例 2:RS256 公钥攻击
-
服务器使用
RS256
算法,密钥未正确管理 -
攻击者从接口泄露中得到公钥
-
将 alg 改为
HS256
-
用公钥作为签名 key 签发 token
成功冒充管理员。
5.6 修复建议(防御策略)
防御点 | 描述 |
---|---|
禁用 alg:none | 强制后端拒绝 none 算法 |
使用强密钥 | 密钥足够复杂,避免爆破 |
使用库强制验签 | jwt.decode(..., verify=True) |
RS256 用正确密钥验证 | 私钥签名,公钥验证,不可混用 |
签名前验证 alg | 不允许客户端自定义算法字段 |
设置过期时间 | JWT 应设定过期防止长期使用 |
不将敏感信息放入 payload | JWT 可解码,敏感字段应加密或不使用 |
5.7 测试工具推荐
工具名 | 作用 |
---|---|
jwt_tool | 自动爆破、篡改、伪造 JWT |
Burp Suite + JWT 插件 | 修改 JWT、尝试自动篡改 |
jwt.io | 在线解码和调试 JWT |
hackvertor | Burp 插件,可动态生成 JWT |
jwt-cracker.py | 弱口令爆破 key |
5.8 SRC 挖掘技巧
-
抓包查看登录接口是否使用 JWT
-
解码 JWT,查看 payload 有无敏感字段(如 admin)
-
尝试改为 alg: none 或修改 payload,观察返回是否变化
-
尝试篡改 token 中角色信息,看是否存在权限绕过
-
检查是否有公钥泄露、算法混用风险
5.9 小结
“JWT 本质是可被前端篡改的身份声明,如果签名不严格校验,就等于攻击者可以随意伪造身份。”
六、Token 重放
Token 重放(Token Replay)攻击,指攻击者截获合法用户的认证 Token(如 JWT、Session Token、OAuth Token 等),并在有效期内反复使用该 Token向服务器发起请求,从而冒充合法用户完成未授权操作。
本质是“窃取的凭证被多次复用”,类似于“抓包后重复发送同一个有效的登录凭证”。
6.1 Token 重放攻击的典型场景
-
用户登录后,浏览器持有访问令牌
-
攻击者通过抓包、XSS、网络监听等手段截获 Token
-
攻击者多次使用该 Token 发起请求
-
服务器无法区分请求是合法用户发起还是攻击者发起
-
导致信息泄露、操作重复、交易多次等问题
6.2 为什么会发生 Token 重放?
原因 | 说明 |
---|---|
Token 无状态 | Token 如 JWT 是无状态的,只要 Token 合法且未过期,服务器默认接受 |
Token 缺乏唯一标识 | 无法判断该 Token 是否已被使用过 |
传输过程中无防护 | HTTP 明文传输或劫持导致 Token 泄露 |
服务器缺乏重放检测 | 不存储或校验 Token 使用记录 |
会话管理不足 | Session 未绑定 IP、设备等上下文信息 |
6.3 Token 重放的攻击方式
1)抓包重放
攻击者使用工具抓包拦截 Token(如 Cookie、Authorization Header),反复发送请求。
2)XSS 窃取 Token
恶意脚本窃取浏览器本地存储的 Token,发送给攻击者,攻击者重放请求。
3)CSRF 利用
借助受信任用户的 Token,在第三方网站诱导用户发起恶意请求。
6.4 Token 重放的危害
-
冒充用户,执行敏感操作
-
多次重复操作,导致资金、积分、数据异常
-
绕过认证,窃取隐私数据
-
破坏会话完整性,影响系统安全
6.5 如何检测 Token 重放风险点?
-
监控异常请求
-
同一 Token 来源的 IP、User-Agent 变化剧烈
-
同一 Token 在极短时间内大量请求
-
-
抓包测试
-
拦截 Token 后,重复发送相同请求,观察系统是否允许
-
-
源码审计
-
检查 Token 验证流程是否带有状态校验
-
是否存储 Token 使用记录或会话信息
-
6.6 防御和缓解措施
方法 | 说明 |
---|---|
使用 HTTPS | 防止中间人抓包窃取 Token |
设置 Token 短有效期 | 减少 Token 被重放窗口 |
Token 单次使用 | 服务器保存 Token 状态,使用后立即失效 |
使用刷新 Token 机制 | Access Token 短,刷新 Token 长,提高安全性 |
绑定 Token 与客户端上下文 | IP、User-Agent、设备指纹绑定 |
Token 黑名单 | 发现泄露时加入黑名单,拒绝使用 |
实现请求唯一标识 | 携带随机 nonce,服务端校验是否重复 |
防止 CSRF | 搭配 CSRF Token 使用 |
监控异常行为 | 实时告警异常 Token 使用 |
6.7 Token 重放防御的关键技术示例
1)状态存储与 Token 一次性使用
服务器维护一个“已使用 Token”列表,使用后立即标记失效。
缺点:增加服务器存储压力,失去 Token 无状态优势。
2)Token 绑定上下文
token = generate_token(user_id, ip_address, user_agent)
验证请求时,检查请求的 IP、User-Agent 与 Token 绑定信息是否匹配。
6.8 实战测试示例
抓包:
GET /api/user/profile HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
攻击者反复发送同样请求:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." https://example.com/api/user/profile
观察是否服务器能检测重放。
6.9 小结
-
Token 重放是常见且严重的认证绕过方式
-
解决核心是增加 Token 的唯一性和有效性校验
-
应用 HTTPS 和合理的 Token 生命周期是基础
-
复杂场景下,建议结合状态存储、上下文绑定、黑名单机制
七、前后端分离权限绕过案例(绕过前端控制)
前后端分离架构中,前端负责界面渲染和用户交互,后端负责数据处理和权限校验。
前端权限控制:通常通过页面元素的显示/隐藏、按钮禁用等方式,控制用户操作权限。
问题:如果后端没有严格的权限校验,仅依赖前端控制,就会导致攻击者绕过前端限制,直接构造请求调用后端接口,实现越权操作。
7.1 前端权限控制的本质及局限性
-
本质:前端权限控制是“安全友好提示”,让用户界面只显示允许操作的功能,提升用户体验。
-
局限:
-
前端代码容易被篡改(浏览器调试工具)
-
请求包可被伪造,绕过页面限制
-
不可信任环境,不能承担安全验证职责
-
7.2 前后端分离权限绕过典型案例
案例1:按钮隐藏绕过
场景:
-
普通用户不能看到“删除用户”按钮,管理员才显示。
-
前端通过判断用户角色隐藏按钮。
风险点:
-
后端接口
/api/deleteUser
没有权限校验。 -
攻击者使用抓包工具直接发送
DELETE /api/deleteUser?id=123
请求。
结果:
攻击成功删除用户,绕过了前端隐藏限制。
案例2:接口参数绕过
场景:
-
前端传递用户角色,后端未校验,直接信任参数。
-
请求中携带
role=admin
以获得管理员权限。
风险点:
-
后端没有验证用户身份和角色,仅用前端传参控制权限。
结果:
攻击者修改请求参数直接提升权限。
案例3:菜单权限控制绕过
场景:
-
前端根据权限动态渲染菜单
-
后端接口没有做权限限制
风险点:
-
攻击者直接调用未授权接口,访问敏感数据
7.3 攻击流程
-
分析前端逻辑
利用浏览器开发者工具查看前端隐藏或禁用的操作。 -
抓包分析请求
用 Burp Suite 等工具抓包分析接口请求格式。 -
篡改请求
修改请求参数或直接访问未显示的接口。 -
发送篡改请求
伪造请求,绕过前端限制。
7.4 防御措施
措施 | 说明 |
---|---|
后端严格权限校验 | 任何接口必须校验用户身份和权限,不能信任前端参数 |
细粒度权限控制 | 根据角色、资源、操作权限精细控制访问 |
最小权限原则 | 用户只能访问必须资源 |
输入参数校验 | 防止参数篡改导致权限提升 |
审计日志 | 记录操作日志,便于异常追踪 |
安全测试 | 渗透测试重点检查接口权限校验 |
前端友好提示 | 保持前端权限控制改善 UX,但不作为安全防线 |
7.5 示例代码
后端伪代码权限检查(Python Flask)
@app.route('/api/deleteUser', methods=['DELETE'])
@login_required
def delete_user():user = get_current_user()if not user.is_admin():return jsonify({'error': 'permission denied'}), 403user_id = request.args.get('id')delete_user_by_id(user_id)return jsonify({'msg': 'user deleted'})
7.6 小结
-
前端权限控制只做用户体验优化,不能承担安全职责。
-
所有关键权限校验必须在后端完成。
-
接口设计时遵循最小权限原则,严禁盲目信任任何前端传入参数。
-
权限绕过是渗透测试中最常见风险点之一,重点检测对象。