表单一次性凭证被重复请求作废 (One-Shot Form Credentials Invalidated by Repeat Requests)
结论先说
登录表单里的一次性凭证 —— 隐藏的防伪 token、图形验证码 —— 是「取一次、用一次」的。
在同一个会话里多取一次,上一次的就作废了。
浏览器里这个坑极难自己发现,因为:
- 报错话术指向验证码(「验证码错误」),实际可能是 token 的问题,反之亦然
- 图片/表单看起来正常,受害者看不出任何异常
- 换成无痕、换浏览器、换网络 —— 全都无效,因为它不在本地
用脚本时反而容易避开:一个会话里取一次,立刻用掉,中间不插任何请求。
症状
出现下面任意一条,先怀疑这个:
- 图形验证码肉眼看对了,提交却一直报「验证码错误」
- 换浏览器 / 无痕 / 换网络 / 清 cookie,全部无效
- 同样的操作,手写脚本能过,浏览器不能
- 一次操作里,前端对同一个验证码接口发了多次请求
最后一条最关键。看一次抓包就知道。
排查过程(黑盒,不需要密码)
第 1 步:同一个会话反复取,凭证稳不稳
SID=$(curl -sS -c - -o /dev/null 'https://<host>/login' | awk '/PHPSESSID/{print $7}')
for i in 1 2 3 4 5; do
curl -sS -H "Cookie: PHPSESSID=$SID" 'https://<host>/login' \
| grep -oE 'name="token" value="[a-f0-9]+"'
done每次都不一样 → 这个 token 是每次渲染重新生成的。
第 2 步:抓一次真实失败
抓包要注意别只记请求,要记「哪个请求带了哪个会话」和「响应体」。
关键对比:取凭证那次请求带的 PHPSESSID,和提交那次带的,是不是同一个。
第 3 步:数一数前端发了几次凭证请求
一次操作里发 3 次,就说明有 2 次是白发的 —— 每一次都把前一次的作废。
排查时踩过的坑(四个被我误判又推翻的)
这几条都是看着很像、实测不成立的,记下来省得下次再绕:
| 猜测 | 怎么推翻的 |
|---|---|
| CDN 缓存了验证码图 | 图每次都是新的(字节指纹都不同)。真缓存了图就不会变 |
| 页面缓存发旧 token | 响应头明写 Cache-Control: no-store, no-cache, must-revalidate |
| 浏览器走代理、脚本直连,落到不同后端 | 两条路出口 IP 一模一样(直连和走代理实测同 IP) |
| 两个请求用了不同的 PHPSESSID | 抓包里全程同一个 PHPSESSID |
前端有 indexOf('400') 误判二进制图片 | 实测 60 张图,0 张命中,排除 |
教训:每一条都要用数据打死,别停在"很像"。 上面五条里前四条我都一度当成结论说过。
根因
服务端把凭证实现成「生成新的就覆盖旧的、只保留最新一个」,而前端会在一次操作里发多次请求。
页面加载 -> 取到凭证 A(服务端存 A)
用户点图刷新 -> 取到 B(服务端存 B,A 作废)
再点一次 -> 取到 C(服务端存 C,B 作废)
用户看着屏幕上的 C,却...只要屏上显示的那一次和服务端最后收到的那一次不是同一个,输入就永远对不上。
响应乱序到达时,这两者会分叉。
解法
同会话内「取一次 → 立刻用」,中间不插任何请求。
GET /login -> 拿 token 和 cookie(同一次请求,天然配套)
GET /verify -> 拿验证码图
POST /login -> 立刻提交,用同一个 token给普通用户的绕过办法
没有脚本的时候,也能靠操作习惯绕开:
- 绝对不要点那张验证码图刷新它。 它多半绑了
onClick刷新,点一次服务端就换一个答案 - 打开登录页,看第一张图,直接敲,立刻提交
- 打字期间不刷新、不切标签、不点任何东西
- 图看不清就整页重载,而不是点图
案例记录
cloud.crzhong.cn(铬中智擎,IDCsmart / 智简魔方面板),2026-09-21:
- 用户没有面板密码,只能走「手机号 + 短信验证码」登录
- 浏览器里图形验证码永远报「图形验证码有误」,换无痕、换网络都无效
- 一次操作抓包:成功提交前,前端对
/verify发了 3 次请求(页面加载 1 次 + 用户点图 2 次) - 自建脚本用「单会话取一次立刻提交」,一次就过
- 用户向服务商报障后已修复。修复在服务端 —— 前端 JS 与响应头前后完全一致(
public.js三个时间点 MD5 相同)
相关概念
- Web 登录鉴权 (Session, Cookie, Bearer, JWT) —— CSRF token、Cookie、Session、JWT 的基础关系
- Htpasswd 基础鉴权 —— 另一种 Web 鉴权方式
- CDN 下载提速与缓存排查(CDN Cache Bypass & Download Acceleration) —— 怀疑缓存时先看响应头
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web