Как добавить CAPTCHA на ваш сайт: пошаговое руководство

Боты уже являются частью вашего трафика — видите вы их или нет. Они создают фейковые аккаунты, проверяют украденные пароли и незаметно нагружают ваш бэкенд задолго до того, как кто-то поднимет тревогу. Понимание того, как добвить captcha на ваш сайт, — это разница между восприятием ботов как чего-то второстепенного, и тем, чтобы встраивать защиту от них непосредственно в ваши формы, пользовательские сценарии и инфраструктуру.
Это руководство проведёт вас через два готовых для продакшена варианта внедрения: GeeTest CAPTCHA v3 и Cloudflare Turnstile. По пути вы также узнаете, как получить captcha code (ключи сайта и учётные данные), когда имеет смысл кастомная captcha, как блокировать попытки обхода captcha и как проверить вашу интеграцию с помощью CapMonster Cloud.
Что такое CAPTCHA и зачем она нужна вашему сайту
CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) — это механизм «испытание–ответ», который пытается отличить реальных пользователей от автоматизированных скриптов. Современные решения варьируются от традиционных головоломок с искажённым текстом до невидимого поведенческого анализа и интерактивных задач, таких как слайдер GeeTest.
Без слоя CAPTCHA любая публичная форма на вашем сайте становится уязвимой к:
- Credential stuffing — автоматизированным попыткам входа с использованием утёкших пар «логин/пароль», что часто встречается в абьюз‑трафике.
- Spam submissions — ботам, которые засыпают формы обратной связи, разделы комментариев или страницы отзывов.
- Account enumeration — скриптам, которые «прощупывают» валидные email‑адреса или имена пользователей.
- Scraping — автоматизированному извлечению цен, складских остатков или проприетарного контента.
Компромисс всегда один - безопасность vs. пользовательский опыт: прерывание действий пользователя останавливает ботов, но слишком много неудобства отталкивает реальных пользователей. Cloudflare Turnstile и GeeTest v3 — современные варианты CAPTCHA, которые стараются сбалансировать эти аспекты: Turnstile ориентирован на проверку с минимальным неудобством, а GeeTest v3 использует интерактивные задачи разных типов с поведенческими проверками для обнаружения ботов.
Как получить ваш CAPTCHA Code (ключи и учётные данные)
Прежде чем писать какой-либо код интеграции, вам понадобятся учётные данные, специфичные для конкретного провайдера CAPTCHA.
GeeTest V3
- Создайте аккаунт в панели GeeTest.
- Перейдите в Captcha Dashboard и выберите CAPTCHA v3:

- Перейдите в раздел, где можно создать новую CAPTCHA и зарегистрировать ваш сайт (обычно указывают домены и тип продукта).
- После настройки вы получите CAPTCHA ID (часто обозначается как gt) и приватный Key для серверного взаимодействия.
- Храните эти значения безопасно (например, в переменных окружения), чтобы приложение могло использовать их без хардкода секретов.
Cloudflare Turnstile
- Войдите на dash.cloudflare.com и откройте раздел Application security > Turnstile.

- Нажмите Add widget, введите ваш домен и выберите режим виджета: Managed, Non-interactive или Invisible.
- Установите Pre-clearance в Yes , если сайт работает через Cloudflare Proxy (чтобы избежать повторного показа CAPTCHA).
- После создания Cloudflare выдаёт Site Key (публичный, используется на клиенте) и Secret Key (приватный, используется на сервере).
- Используйте Site Key в вашем HTML или JavaScript, а Secret Key отправляйте только с бэкенда при вызове Turnstile verification API.
Как внедрить GeeTest CAPTCHA v3: пошаговая инструкция
GeeTest v3 использует многошаговый процесс: ваш server получает свежий challenge от GeeTest, затем client отрисовывает задачу, используя этот challenge (GeeTest API1), и после этого ваш server проверяет решённые токены (GeeTest API2). Ниже приведён пример реализации на PHP + JavaScript, иллюстрирующий этот паттерн; адаптируйте его под официальный SDK GeeTest и выбранный вами язык.
Шаг 1 — эндпоинт регистрации на стороне сервера
Создайте PHP-скрипт (например, geetest_register.php), который получает свежий challenge от GeeTest и передаёт его клиенту:
<?php
header('Content-Type: application/json');
const CAPTCHA_ID = '07df3141a35**19a473d7c50';
const CAPTCHA_KEY = '543b19036ef**8e07d121b81e9';
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
function getJson($url) {
$res = @file_get_contents($url);
return $res ? json_decode($res, true) : null;
}
// API1: Инициализация
if ($path === '/register') {
$data = getJson("https://api.geetest.com/register.php?gt=" . CAPTCHA_ID . "&json_format=1");
echo json_encode($data ? [
'gt' => CAPTCHA_ID,
'challenge' => $data['challenge'],
'success' => $data['success'] === 1,
'new_captcha' => true
] : ['success' => 0]);
exit;
}
// API2: Верификация
if ($path === '/validate' && $_SERVER['REQUEST_METHOD'] === 'POST') {
$req = json_decode(file_get_contents('php://input'), true);
$data = getJson("https://api.geetest.com/validate.php?" . http_build_query([
'seccode' => $req['geetest_seccode'] ?? '',
'challenge' => $req['geetest_challenge'] ?? '',
'gt' => CAPTCHA_ID,
'json_format' => 1
]));
echo json_encode(['success' => !empty($data['seccode'])]);
exit;
}
http_response_code(404);
echo json_encode(['error' => 'Not found']);Шаг 2 — инициализация на стороне клиента
Подключите SDK GeeTest и вызовите initGeetest, передав параметры с сервера (API1). Пример с использованием ajax:
ajax({
url: "https://example.com/register",
type: "get",
dataType: "json",
success: function (data) {
initGeetest({
gt: data.gt,
challenge: data.challenge,
offline: !data.success,
new_captcha: true
}, function (captchaObj) {
captchaObj.appendTo("#captcha");
captchaObj.onSuccess(function () {
const result = captchaObj.getValidate();
ajax({
url: "https://example.com/validate",
type: "post",
contentType: "application/json",
data: JSON.stringify(result),
success: function(res) {
if (res.success) alert('CAPTCHA passed');
else alert('CAPTCHA failed');
}
});
});
});
}
});Проверка работы
Убедитесь, что:
- /register возвращает challenge
- Капча отображается корректно
- После прохождения капчи запрос на /validate виден в консоли браузера
- Сервер возвращает "success": true
Failback (режим fallback)
Если сервер GeeTest недоступен:
- Клиент получает success: false
- Капча переключается в локальный режим (работает без подключения к GeeTest Cloud). Чтобы проверить это, просто подставьте некорректный CAPTCHA_ID (например, 123456789).
Примечание: GeeTest также предоставляет официальные server-side SDK для разных платформ и языков — вы можете выбрать тот, который соответствует вашему технологическому стеку. Подробнее — в официальной документации GeeTest CAPTCHA v3.
Как внедрить Cloudflare Turnstile: пошагая инструкция
У Cloudflare Turnstile нет отдельного серверного «registration call». Вы встраиваете виджет на страницу, позволяете ему сгенерировать токен, а затем проверяете этот токен на стороне сервера через Siteverify API от Cloudflare.
Шаг 1 — Подключите скрипт Turnstile
Автоматический рендеринг (виджет создаётся автоматически при загрузке страницы):
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>Программное управление (вы создаёте виджет самостоятельно через JavaScript):
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit" defer></script>Важно: скрипт должен быть загружен с точного URL. Прокси или кэш могут привести к сбоям.
Шаг 2 — Создайте контейнер для виджета
Авто:
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>"></div>Программно:
<div id="turnstile-container"></div>Шаг 3 — Настройка виджета
Через data-атрибуты:
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>" data-theme="light" data-size="normal" data-callback="onSuccess"> </div>Через JavaScript:
const widgetId = turnstile.render("#turnstile-container", {
sitekey: "<YOUR_SITEKEY>",
theme: "light",
size: "normal",
callback: token => console.log("Token:", token)
});Шаг 4 — Работа с токенами
const token = turnstile.getResponse(widgetId); // получение токена
const isExpired = turnstile.isExpired(widgetId); // проверка срока действительности токена
turnstile.reset(widgetId); // сброс
turnstile.remove(widgetId); // удаление
turnstile.execute("#turnstile-container"); // ручное извлечениеШаг 5 — Интеграция с формой
<form id="my-form" method="POST">
<input type="hidden" name="cf-turnstile-response" id="cf-turnstile-response">
<button type="submit">Submit</button>
</form>
<script>
function onSuccess(token) {
document.getElementById("cf-turnstile-response").value = token;
}
</script>Полный пример кода
<html>
<title>Turnstile Example</title> <!-- Подключение скрипта Turnstile -->
<head>
<script src="https: //challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
<h1>Form example with Turnstile</h1>
<form id="my-form"> <label for="username">Name:</label> <input type="text" name="username" id="username" required> <!-- Контейнер для Turnstile -->
<div class="cf-turnstile" data-sitekey="<YOUR_SITEKEY>" data-callback="onTurnstileSuccess"></div> <button type="submit">Submit</button>
</form>
<script>
// Callback, вызываемый после прохождения CAPTCHA
function onTurnstileSuccess(token) {
console.log("Received Turnstile token:", token);
// Save token to hidden form field (optional)
document.getElementById("cf-turnstile-token") ? .remove();
const input = document.createElement("input");
input.type = "hidden";
input.name = "cf-turnstile-response";
input.id = "cf-turnstile-token";
input.value = token;
document.getElementById("my-form").appendChild(input);
}
// Отправка формы
document.getElementById("my-form").addEventListener("submit", async(e) => {
e.preventDefault();
const formData = new FormData(e.target);
const response = await fetch("/submit-form", {
method: "POST",
body: formData
});
const result = await response.json();
if(result.success) {
alert("Form successfully submitted and token verified!");
}
else {
alert("Turnstile token verification error. Please try again.");
// Reset widget so the user can complete the CAPTCHA again
turnstile.reset();
}
});
</script>
</body>
</html>Шаг 6 — Настройте серверную часть
Процесс проверки на стороне сервера:
- Клиент: пользователь проходит Turnstile на странице → создаётся токен.
- Форма отправляется: токен вместе с данными формы отправляется на сервер.
- Сервер: делает POST-запрос к Cloudflare Siteverify API с токеном и секретом.
- Cloudflare: возвращает JSON с результатом (success: true/false) и дополнительной информацией (action, hostname, completion time).
- Сервер: решает, разрешить или отклонить действие пользователя.
Siteverify API:
POST
https://challenges.cloudflare.com/turnstile/v0/siteverifyПараметры запроса:
- secret (обязательно): секретный ключ Turnstile из панели Cloudflare
- response (обязательно): токен, полученный на клиенте
- remoteip (необязательно): IP-адрес пользователя (рекомендуется)
- idempotency_key (необязательно): уникальный UUID для защиты от повторных верификаций
Свойства токена:
- Максимальная длина: 2048 символов
- Действителен 5 минут
- Одноразовый (single-use)
- При истечении срока действия или повторной верификации API вернёт ошибку timeout-or-duplicate
Пример проверки на PHP:
<?php
function validateTurnstile($token, $secret, $remoteip = null) {
$url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
$data = ['secret' => $secret,
'response' => $token];
if ($remoteip) $data['remoteip'] = $remoteip;
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded
",
'method' => 'POST',
'content' => http_build_query($data)
]
];
$response = file_get_contents($url, false, stream_context_create($options));
if ($response === FALSE) {
return ['success' => false,
'error-codes' => ['internal-error']];
}
return json_decode($response, true);
}
$secret_key = 'YOUR_SECRET_KEY';
$token = $_POST['cf-turnstile-response'] ?? '';
$remoteip = $_SERVER['REMOTE_ADDR'];
$result = validateTurnstile($token, $secret_key, $remoteip);
if ($result['success']) {
echo "Form successfully submitted!";
} else {
echo "Verification error: " . implode(', ', $result['error-codes']);
}
?>Примечание: Все подробные инструкции по установке и настройке Cloudflare Turnstile, включая клиентскую и серверную интеграцию, примеры кода, описания ошибок и рекомендации по безопасности, можно найти в официальной документации Cloudflare.
Создание собственной CAPTCHA: когда и зачем
Любая кастомная captcha — это система «задача–ответ», которую вы создаёте сами вместо интеграции стороннего сервиса. Распространённые лёгкие подходы включают:
- Math puzzles — «Сколько будет 4 + 9?», показанное как обычный текст или простое сгенерированное изображение.
- Honeypot fields — скрытые поля формы, которые обычно заполняют только боты.
- Time-based checks — отклонение отправок, выполненных нереалистично быстро для человека.
- Custom image challenges — «Выберите лишний предмет» с использованием ваших собственных ассетов.
Кастомные captcha могут быть полезны, когда вам нужен строгий контроль над брендингом, когда жёсткие требования к приватности ограничивают использование сторонних капч, или когда ваш риск‑профиль низкий и вам достаточно базовой защиты от ботов. Однако им обычно не хватает продвинутых поведенческих моделей сервисов вроде GeeTest или Turnstile, и их может быть проще «победить» продвинутым ботам.
Вы также берёте на себя полную ответственность за доступность капчи для людей с ограниченными возможностями (например, предоставление аудио‑альтернатив) и постоянное сопровождение по мере того, как эволюционируют техники ботов. Для критичных сценариев вроде логина, оформления заказа или сброса пароля управляемое стороннее решение обычно безопаснее полностью кастомной captcha.
Как эффективно блокировать CAPTCHA-ботов
Внедрение CAPTCHA необходимо, но редко бывает достаточным само по себе: целеустремлённые атакующие скрипты попытаются обойти её или автоматизировать. Чтобы эффективнее блокировать captcha‑ботов, комбинируйте несколько уровней.
Уровень 1 — Rate limiting на уровне инфраструктуры
Rate limiting на уровне веб‑сервера или CDN усложняет ботам перебор форм (brute force), даже если они умеют решать или обходить captcha. Например, в Nginx:
# Nginx: limit login endpoint to 10 req/s per IP
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/s;
location /login {
limit_req zone=login burst=5 nodelay;
# proxy_pass ...
}Уровень 2 — Honeypot-поля
Скрытое поле, которого реальные пользователи никогда не видят, но которое могут заполнить несложные боты, — это защита с минимальным неудобством для пользователя.
<div aria-hidden="true">
<input type="text" name="website" tabindex="-1" autocomplete="off">
</div>На сервере отклоняйте любую отправку, где name="website". Это почти не влияет на UX и при этом отфильтровывает часть автоматизированных отправок.
Уровень 3 — Дополнительные слои защиты
- IP reputation filtering: блокирование известных диапазонов дата‑центров или сервисов анонимизации может существенно сократить абьюз‑трафик.
- Token replay prevention: токены Turnstile необходимо валидировать на стороне сервера и считать одноразовыми; отбрасывание повторно используемых токенов помогает предотвращать replay‑атаки.
- Device or session fingerprinting: внешние инструменты могут помочь коррелировать подозрительные паттерны между IP и сессиями, хотя это заставляет проверить политику приватности.
- Monitoring and alerting: отслеживайте долю неуспешных проверок и резкие всплески трафика из конкретных регионов или ASN как сигналы продолжающейся атаки.
Тестирование интеграции CAPTCHA с CapMonster Cloud
Когда ваша CAPTCHA уже работает в продакшене, вам нужен надёжный способ прогонять весь цикл request-response в автоматизированных тестовых пайплайнах — без необходимости вручную решать головоломки на каждом прогоне CI. CapMonster Cloud — это API-ориентированный сервис решения CAPTCHA, который поддерживает, среди прочего, GeeTest v3 и Cloudflare Turnstile. Вы отправляете задачу (task), описывающую капчу, которую нужно решить, а API возвращает токены решения, которые ваши тесты могут напрямую подставить в отправку формы.
Полный сценарий для обоих типов CAPTCHA состоит из одних и тех же трёх шагов: создать задачу → опрашивать результат → использовать решение.
GeeTest V3 — полный сценарий работы CapMonster Cloud
Шаг 1 — Создайте задачу
Вызывайте createTask сразу после получения свежего challenge из вашего регистрационного эндпоинта GeeTest. Значение challenge живёт недолго и используется только один раз.
Запрос:
POST https://api.capmonster.cloud/createTask
{
"clientKey": "YOUR_CAPMONSTER_API_KEY",
"task": {
"type": "GeeTestTask",
"websiteURL": "https://example.com/your-page",
"gt": "022397c99c9f646f6477822485f30404",
"challenge": "7f044f48bc951ecfbfc03842b5e1fe59",
"geetestApiServerSubdomain": "api-na.geetest.com"
}
}Ответ:
{
"errorId": 0,
"taskId": 407533072
}Шаг 2 — Опрашивайте результат
Вызывайте getTaskResult в цикле, ожидая несколько секунд между опросами. Задачи GeeTest V3 обычно завершаются за 10–30 секунд в зависимости от нагрузки системы.
Запрос:
POST https://api.capmonster.cloud/getTaskResult
{
"clientKey": "YOUR_CAPMONSTER_API_KEY",
"taskId": 407533072
}Ответ, пока идёт решение:
{
"errorId":0,
"status":"processing"
}Ответ, когда готово:
{
"errorId":0,
"status":"ready",
"solution":{
"challenge":"0f759dd1ea6c4wc76cedc2991039ca4f23",
"validate":"6275e26419211d1f526e674d97110e15",
"seccode":"510cd9735583edcb158601067195a5eb|jordan"
}
}Все три значения в solution — challenge, validate и seccode — должны отправляться на ваш backend вместе, ровно так же, как это сделал бы реальный браузер.
Шаг 3 — Отправьте решение
Отправьте три значения решения на эндпоинт формы в тех же полях тела запроса, которых ожидает ваша интеграция GeeTest:
const result = await pollForResult(taskId);
await fetch('/submit_form.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
geetest_challenge: result.solution.challenge,
geetest_validate: result.solution.validate,
geetest_seccode: result.solution.seccode,
})
});Cloudflare Turnstile — полный сценарий работы CapMonster Cloud
Шаг 1 — Создайте задачу
Запрос:
POST https://api.capmonster.cloud/createTask
{
"clientKey": "API_KEY",
"task": {
"type": "TurnstileTask",
"websiteURL": "http://tsmanaged.zlsupport.com",
"websiteKey": "0x4AAAAAAABUYP0XeMJF0xoy"
}
}Описание параметров см. в документации CapMonster.
Ответ:
{
"errorId": 0,
"taskId": 407533072
}Шаг 2 — Опрашивайте результат
Задачи Turnstile обычно завершаются за 5–20 секунд.
Запрос:
POST https://api.capmonster.cloud/getTaskResult
{
"clientKey": "YOUR_CAPMONSTER_API_KEY",
"taskId": 407533072
}Ответ, пока идёт решение:
{
"errorId": 0,
"status": "processing"
}Ответ, когда готово:
{
"errorId": 0,
"status": "ready",
"solution": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
"token": "0.iGX3xsyFCkbGePM3jP4P4khLo6TrLukt8ZzBvwuQOvbC...f61f3082"
}
}solution.token — это значение, которое подставляется в cf-turnstile-response при отправке формы. Используйте solution.userAgent в вашем HTTP-клиенте или в инстансе Playwright/Selenium, чтобы совпадала среда, в которой токен был решён — несовпадения могут приводить к отклонению на стороне сервера.
Шаг 3 — Отправьте решение
Подставьте решённый токен перед отправкой формы — либо напрямую в скрытое поле input, либо через JavaScript callback Cloudflare:
// Вариант A: прямая инъекция в DOM (для тестов Playwright/Selenium)
await page.evaluate(token => {
const field = document.querySelector('[name="cf-turnstile-response"]');
if (field) field.value = token;
}, result.solution.token);
// Вариант B: напрямую вызвать callback Turnstile (для тестов SPA)
await page.evaluate(token => {
if (window.turnstileCallback) window.turnstileCallback(token);
}, result.solution.token);
await page.click('#submit-btn');Обработка ошибок CapMonster Cloud
И createTask, и getTaskResult используют один и тот же «конверт» ошибок. Значение errorId равное 0 всегда означает успех; значение errorId: 1 сигнализирует о проблеме, а конкретный тип ошибки возвращается в строковом поле errorCode. Полный список возможных ошибок см. в документации CapMonster.
Пример ответа с ошибкой:
{
"errorId": 1,
"errorCode": "ERROR_KEY_DOES_NOT_EXIST"
}Лучшие практики и советы
Корректно обрабатывайте истечение срока действия токена
GeeTest challenges и токены Turnstile ограничены по времени, поэтому стоит ожидать периодических истечений срока действия, если пользователи слишком долго тянут с отправкой формы. Реализуйте callbacks вроде expired-callback у Turnstile либо заново запрашивайте свежий challenge GeeTest и сбрасывайте виджет.
Доступность для людей с ограниченными возможностями (WCAG 2.1)
Cloudflare Turnstile предоставляет визуальные и альтернативные сценарии прохождения проверки, рассчитанные на работу с ассистивными технологиями, но вам стоит протестировать их со скринридерами и браузерами, на которые полагаются ваши пользователи.
Слайдер-головоломка GeeTest v3 ориентирована на мышь/тач, что может создавать сложности для пользователей с определёнными двигательными нарушениями или нарушениями координации; подумайте об альтернативном пути верификации там, где требуется высокая доступность вашего сервиса.
Не делайте CAPTCHA единственным механизмом защиты в критически важных сценариях для пользователей с инвалидностью; комбинируйте её с другими мерами, такими как rate limiting и обнаружение аномалий.
Приватность сбора данных
Использование Turnstile или GeeTest предполагает отправку данных о запросах и взаимодействии третьей стороне (провайдеру) для анализа и верификации. В вашей политике конфиденциальности и механизмах согласия это должно быть отражено, особенно в рамках таких режимов, как GDPR или CCPA, где такая обработка может считаться обработкой персональных данных.
Применяйте CAPTCHA стратегически — не везде
Разделяйте тестовые и продакшен-ключи
Cloudflare и большинство провайдеров CAPTCHA рекомендуют использовать отдельные ключи или окружения для development, staging и production. Храните ваш Secret Key и любые аналогичные приватные ключи в переменных окружения или в специализированном менеджере секретов, а не хардкодьте их.
Обновляйте SDK и интеграции
Сервисы CAPTCHA со временем обновляют логику детектирования и API в ответ на новые техники атак. Периодический просмотр changelog’ов или документации провайдера и обновление интеграций помогает избежать использования устаревших эндпоинтов или ослабленных конфигураций.
Заключение
Понимание того, как правильно внедрить CAPTCHA, — это больше, чем просто вставить виджет в HTML; важно сочетать надёжный клиентский сценарий с корректной серверной верификацией и оборачивать всё это в более объемную стратегию защиты от ботов. GeeTest v3 предлагает поведенческую головоломку, которая может поднять планку для операторов ботов, а Cloudflare Turnstile естественно вписывается в сайты на Cloudflare и делает акцент на верификацию с минимальным прерыванием действий пользователя.
Какой бы вариант вы ни выбрали, сочетание CAPTCHA с rate limiting, honeypot-полями и фильтрацией по репутации IP значительно увеличивает усилия, необходимые для злоупотребления вашим сайтом. А когда вам нужно протестировать интеграцию или автоматизировать сложные сценарии, CapMonster Cloud даёт вам программный способ решать задачи GeeTest и Cloudflare Turnstile через простой API.
Готовы добавить автоматизированное тестирование CAPTCHA в свой инструментарий? Изучите решение CapMonster Cloud и начните интегрировать решение капч GeeTest и Turnstile в ваши процессы разработки и QA уже сегодня.






