Срок действия токена reCAPTCHA: как долго токены остаются валидными

recaptcha token expiration - reCAPTCHA Token Expiration: How Long Tokens Stay Valid

Срок действия токена reCAPTCHA составляет две минуты. Документация Google говорит об этом прямо: каждый токен-ответ действителен две минуты и может быть проверен только один раз. Промахнётесь с любой из двух половин, и сервер вернёт вам одну и ту же бесполезную ошибку. В этой статье разбираются три отдельных таймера, которые принимают за один, куда на самом деле уходят эти 120 секунд в автоматизированном сценарии, и изменение порядка действий, которое устраняет почти любой баг с истёкшим токеном.

Две минуты и ровно одна проверка

У правила две половины, и обе кусаются.

Две минуты. Отсчёт начинается в момент выдачи токена, а не в момент отправки формы. Токен, который лежит в скрытом поле, пока пользователь дописывает текст, уже тратит свой бюджет.

Одна проверка. Отправка одного и того же токена в Google второй раз завершается ошибкой, даже через секунду. Так задумано: именно это не даёт переиграть перехваченный токен. Если ваш бэкенд проверяет токен один раз в middleware и ещё раз в обработчике, второй вызов падает, и баг выглядит плавающим.

Оба сбоя возвращают одно и то же. Ответ проверки от Google приходит с success, равным false, и кодом ошибки timeout-or-duplicate, который означает, что ответ либо слишком старый, либо уже был использован. Какой именно случай, он не сообщает, поэтому считайте это одним классом ошибок и проверяйте оба варианта.

Три таймера, а не один

Основная путаница здесь возникает из-за того, что три разных таймера сводят к одному понятию “срок действия токена”. Они разные и истекают независимо друг от друга.

ТаймерДлительностьЧто происходит, когда он истекает
Собственный ответ виджета, v2 checkbox2 минутыВиджет очищает себя и вызывает expired callback. Скрытое поле становится пустым
Токен-ответ, на стороне сервера2 минутыПроверка возвращает timeout-or-duplicate
Ваша сессия на целевом сайтеЗависит от сайтаНе связано с reCAPTCHA. Свежий токен не починит мёртвую сессию

Первого таймера никто не ждёт, потому что он работает на стороне клиента и молча. На v2 checkbox виджет через две минуты сам аннулирует свой ответ и вызывает ту функцию, которую вы зарегистрировали как expired callback. Если вы не зарегистрировали ничего, отмеченный флажок так и остаётся отмеченным на экране, хотя скрытое поле за ним пустое, поэтому форма уходит вообще без токена, и сервер сообщает об ошибке отсутствующего ввода, а не об истёкшем сроке.

<!-- 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Срок действия токенаПовторное использование
reCAPTCHA v2, checkbox и Invisible2 минутыНет
reCAPTCHA v32 минутыНет
reCAPTCHA Enterprise2 минутыНет
Cloudflare Turnstile5 минутНет
GeeTest v3Отправляйте его обратно сразуНет

Turnstile здесь самый щедрый. Руководство Cloudflare по серверной валидации даёт токену 300 секунд и отклоняет повторно отправленный с тем же кодом timeout-or-duplicate, который использует Google. GeeTest v3 работает наоборот: значение challenge, которое вы передаёте на решение, одноразовое и истекает примерно за минуту, поэтому дедлайн наступает до решения, а не после него. Получайте его непосредственно перед решением, а не в начале скрипта.

Куда на самом деле уходят две минуты

При ручном заполнении формы бюджет огромен. В автоматизированном сценарии он теснее, чем кажется, потому что решение не мгновенное.

ШагТипичное время
Загрузить страницу и прочитать sitekeyот 1 до 3 секунд
Решить reCAPTCHA v2от 15 до 20 секунд
Решить reCAPTCHA v3От 10 до 15 секунд
Вставить токен и отправитьменьше секунды
Остаётсяпримерно 95 секунд

Запас в девяносто пять секунд выглядит комфортно, пока в середину не влезает что-то ещё. Обычные виновники: рукопожатие прокси, шаг входа, вставленный между решением и отправкой, ограничитель частоты, который усыпляет воркер, или очередь, которая копит решённые токены для последующего использования. Последнее не работает никогда: токен быстро портится и не является ресурсом, который можно складывать в пул.

Берите токен последним

Почти любой баг с истёкшим токеном лечится порядком действий. Сначала делайте всё медленное, а токен берите последним шагом перед запросом, который его расходует.

# 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"]})

Из этого следуют два правила, и они покрывают почти всё остальное.

  • Никогда не кэшируйте токен. Ни в Redis, ни в переменной, которая живёт дольше запроса, ни между повторами. Вместо этого решайте заново
  • Никогда не проверяйте дважды. Проверяйте ровно в одном месте. Если middleware уже проверил токен, обработчик маршрута должен прочитать этот результат, а не вызывать Google снова

Повторы заслуживают отдельного слова. Если отправка не удалась и вы её повторяете, уже отправленный токен израсходован, поэтому повтору нужно новое решение. Повторять всю единицу работы правильно. Повторять только HTTP-вызов со старым токеном означает получать timeout-or-duplicate каждый раз, и выглядит это так, будто решатель возвращает плохие ответы.

Задержки и место запуска решателя

Поскольку CapSkip работает на вашем собственном железе, ни одна секунда двухминутного бюджета не уходит на обращение к стороннему эндпоинту через интернет. Local mode слушает 127.0.0.1, и вызов вообще не покидает машину.

Server mode меняет это немного, и стоит знать, насколько. Если направить воркеры на общий решатель в вашей сети или на VPS с публичным IP, добавляется один сетевой хоп на вызов: миллисекунды в локальной сети и десятки миллисекунд до VPS в том же регионе. На фоне 120 секунд это шум, зато вы получаете один решатель, обслуживающий весь флот. Оба режима настраиваются в разделе Настройки подключения, а для серверного варианта рекомендуется статический публичный IP.

Сюда же относится одна деталь CapSkip: решённый результат читается один раз. Повторный опрос того же идентификатора задачи не вернёт ответ снова, поэтому сохраняйте токен при первом чтении, а не запрашивайте его позже заново.

FAQ

Можно ли продлить эти две минуты?

Нет. Окно задаёт Google, и нет ни настройки сайта, ни параметра, ни тарифа, которые бы это меняли. Единственный доступный рычаг: делать меньше между решением и отправкой.

Истекает ли токен v3 быстрее из-за оценки?

Нет. Токены v3 получают те же две минуты, что и v2. Оценка относится совсем к другому: она описывает, как выглядел трафик, а не сколько живёт ответ, и она не снижается, пока токен лежит без дела. Учтите, что в CapSkip нет опции минимальной оценки, поэтому на стороне решения с ней тоже ничего не связано.

Локально мой токен работает, а в продакшене истекает. Почему?

Почти всегда виновата очередь. Локальные запуски идут прямо от решения к отправке, а в продакшене задача сначала проходит через брокер, пул воркеров или ограничитель частоты. Измерьте разрыв между двумя отметками времени в продакшене, и обычно окажется, что он больше 120 секунд. Перенесите решение в тот воркер, который выполняет отправку.

Бывает ли timeout-or-duplicate виной самого сайта?

Иногда. Страница, которая сама проверяет токен перед тем, как переслать ваш запрос, израсходует его, и ваша собственная проверка после этого падает как дубликат. Прокси-слои и веб-файрволы приложений иногда делают то же самое. Если токен падает при первом использовании со свежей отметкой времени, подозревайте, что его потратил кто-то выше по цепочке.

Коротко

Две минуты, одна проверка и три отдельных таймера, которые принимают за один. Зарегистрируйте expired callback, чтобы браузерный случай был виден, решайте как можно позже и никогда не кэшируйте и не переигрывайте токен. Поскольку решать заново ничего не стоит, когда у вас есть локальный сервис распознавания капчи, повторное решение всегда будет правильным ответом на истёкший токен. Механику каждой версии смотрите в руководстве по reCAPTCHA v2 и руководстве по v3, странице Turnstile для случая с пятью минутами, а также в материале о том, что такое reCAPTCHA для общего контекста.