reCAPTCHA token 过期时间:token 能保持多久有效

reCAPTCHA 的 token 过期时间是两分钟。Google 的文档说得很直白:每个响应 token 有效期为两分钟,并且只能验证一次。任何一半没做到,你的服务器拿回来的都是同一个没什么用的错误。本文讲清人们常常混为一谈的三个计时器、在自动化流程里这 120 秒究竟花在了哪里,以及那个能修掉几乎所有 token 过期 bug 的顺序调整。
两分钟,而且只能验证一次
这条规则分成两半,两半都会让你吃亏。
两分钟。 计时从 token 签发那一刻开始,而不是从你提交表单开始。一个躺在隐藏字段里、等着用户把字打完的 token,已经在消耗自己的额度了。
只验证一次。 把同一个 token 发给 Google 两次,第二次一定失败,哪怕只隔了一秒。这是有意为之:正是它挡住了被截获的 token 被重放。如果你的后端在中间件里验证一次、在处理函数里又验证一次,第二次调用就会失败,而这个 bug 看起来是时好时坏的。
两种失败返回的是同一个东西。Google 的 验证响应 会返回 success 为 false,并附带错误代码 timeout-or-duplicate,意思是该响应要么太旧,要么已经被用过。它不会告诉你是哪一种,所以把两者当成同一类 bug,两边都查。
是三个计时器,不是一个
这里的多数困惑,来自把三个不同的计时器压缩成一个 “token 过期” 的概念。它们是分开的,各自独立到期。
| 计时器 | 时长 | 到期后会发生什么 |
|---|---|---|
| 小组件自身的响应,v2 复选框 | 2 分钟 | 小组件会自行清空并触发过期回调。隐藏字段变为空 |
| 响应 token,服务端 | 2 分钟 | 验证返回 timeout-or-duplicate |
| 你在目标站点上的会话 | 因站点而异 | 与 reCAPTCHA 无关。会话已经失效时,换一个新 token 也救不回来 |
第一个计时器是人们从来没预料到的,因为它在客户端而且悄无声息。在 v2 复选框上,小组件会在两分钟后作废自己的答案,并调用你注册为过期回调的那个函数。如果你什么都没注册,屏幕上的勾还打着,它背后的隐藏字段却已经空了,于是表单在完全没有 token 的情况下提交,服务器报的是缺少输入的错误,而不是过期错误。
<!-- Register the callback. Without it the box looks ticked
while the value behind it is already gone. -->
<div class="g-recaptcha"
data-sitekey="YOUR_SITEKEY"
data-callback="onSolved"
data-expired-callback="onExpired"></div>
<script>
function onExpired() {
// Reset the widget and re-enable whatever you disabled.
grecaptcha.reset();
}
</script>其他类型的挑战能撑多久?
两分钟并不是通用值。如果你要处理不止一种挑战类型,这些额度的差别大到值得留意。
| Challenge | token 有效期 | 可否复用 |
|---|---|---|
| reCAPTCHA v2,复选框与 Invisible | 2 分钟 | 否 |
| reCAPTCHA v3 | 2 分钟 | 否 |
| reCAPTCHA Enterprise | 2 分钟 | 否 |
| Cloudflare Turnstile | 5 分钟 | 否 |
| 极验 v3 | 立即把它回传 | 否 |
Turnstile 是最宽松的那个。Cloudflare 的 服务端校验指南 给了 token 300 秒,并且用与 Google 相同的 timeout-or-duplicate 代码拒绝被重放的 token。极验(GeeTest)v3 正好反过来:你喂给识别过程的挑战值是一次性的,大约一分钟就会过期,所以截止时间在识别之前,而不是之后。要在识别之前马上去取它,绝不要放在脚本开头。
这两分钟究竟花在了哪里
在人工填写的表单里,这个额度绰绰有余。在自动化流程里,它比看上去要紧张,因为识别不是瞬间完成的。
| 步骤 | 典型耗时 |
|---|---|
| 加载页面并读取 sitekey | 1 到 3 秒 |
| 识别一个 reCAPTCHA v2 | 15 到 20 秒 |
| 识别一个 reCAPTCHA v3 | 10 到 15 秒 |
| 注入 token 并提交 | 不到一秒 |
| 剩余 | 大约 95 秒 |
九十五秒的余量本来很宽裕,直到中间又插进别的东西。常见的元凶有:代理握手、在识别和提交之间插入的登录步骤、让 worker 睡眠的限流器,或者把识别好的 token 攒起来留着以后用的队列。最后一种永远不管用:token 是易腐品,不是可以放进池子里的资源。
最后一步才去拿 token
几乎所有 token 过期 bug 的修法都是调整顺序。先把慢的事情全部做完,把取 token 放在会消耗它的那次请求之前的最后一步。
# pip install capskip
from capskip import CapSkip
solver = CapSkip(host="127.0.0.1", port=8080)
# Slow things first: log in, warm the session, pick up cookies.
session = build_session()
sitekey = read_sitekey(session, PAGE_URL)
# Then solve, so the clock starts as late as possible.
result = solver.recaptcha(sitekey=sitekey, url=PAGE_URL)
# And submit straight away. Nothing goes between these two lines.
session.post(PAGE_URL, data={"g-recaptcha-response": result["code"]})由此得出两条规则,剩下的情况大多能被它们覆盖。
- 永远不要缓存 token。 不要放进 Redis,不要放进生命周期长过本次请求的变量,也不要跨重试沿用。重新识别一次就好
- 永远不要验证两次。 只在一个地方验证。如果中间件已经检查过 token,路由处理函数就必须读取那个结果,而不是再去调一次 Google
重试值得单独说一句。如果提交失败后你去重试,之前发出去的那个 token 已经用掉了,所以重试需要一次新的识别。重试整个工作单元是对的。只重试 HTTP 调用、还带着旧 token,你每次都会拿到 timeout-or-duplicate,看起来就像识别工具在返回错误答案。
延迟,以及识别工具跑在哪里
因为 CapSkip 跑在你自己的硬件上,这两分钟的额度里没有一点花在穿过互联网去够第三方端点上。Local 模式监听 127.0.0.1,这次调用根本不会离开本机。
Server 模式会稍微改变这一点,值得知道改变了多少。把你的 worker 指向内网里、或者某台有公网 IP 的 VPS 上的共享识别工具,每次调用会多一跳网络,在局域网里是几毫秒,到同区域的 VPS 是几十毫秒。相对 120 秒来说这是噪声,换来的是一个识别工具服务整个集群。两种模式都配置在 连接设置,而 Server 这种场景建议配一个静态公网 IP。
还有一个 CapSkip 的细节属于这里:识别结果只能读取一次。第二次轮询同一个任务 id 不会再返回答案,所以第一次读到 token 时就把它存下来,不要指望之后再去取。
常见问题
我能延长这两分钟吗?
不能。这个窗口由 Google 强制执行,没有任何站点设置、参数或套餐能改变它。你唯一的杠杆是在识别和提交之间少做点事。
v3 的 token 会因为分数而过期得更快吗?
不会。v3 的 token 和 v2 一样是两分钟。分数完全是另一回事:它描述的是流量看起来怎么样,而不是答案能存活多久,而且 token 闲置期间分数也不会衰减。另外要注意,CapSkip 没有最低分数选项,所以识别这一侧也没有任何东西和它挂钩。
我的 token 在本地能用,到了生产环境就过期了,为什么?
几乎总是队列的问题。本地运行是从识别直接走到提交,而生产环境会先把任务丢进消息中间件、worker 池或限流器。在生产环境里量一下这两个时间戳之间的间隔,通常会发现超过了 120 秒。把识别挪到真正执行提交的那个 worker 上。
timeout-or-duplicate 有可能是站点自己的问题吗?
有时候是。如果页面在转发你的请求之前自己先验证了 token,它就已经把 token 消耗掉了,于是你自己的验证就以重复告终。代理层和 Web 应用防火墙偶尔也会这么干。如果一个 token 第一次使用、时间戳也很干净却还是失败,那就怀疑是上游的某个环节把它用掉了。
简短版结论
两分钟,一次验证,以及三个被人们当成一个的独立计时器。注册过期回调,让浏览器端的情况看得见;尽量晚一点再识别;永远不要缓存或重放 token。既然在 本地验证码识别工具上重新识别一次不花任何成本,那么面对过期的 token,再识别一次永远是正确答案。各个版本的具体机制,请参见 reCAPTCHA v2 指南 和 v3 指南, Turnstile 页面 了解五分钟的那种情况;另外还有 什么是 reCAPTCHA 可以了解背景知识。
