Капча к форме в Laravel 11: подходы и цена решения
Форма обратной связи собирает по сотне спам-заявок в день. Разбираем три способа подключить капчу к Laravel — от honeypot до Google reCAPTCHA v3 — и что каждый стоит в UX и нагрузке.

Форма заявки на сайте, собранном на Laravel, за неделю набивает базу двумя тысячами записей, из которых руками написаны десять. Остальное — боты, которые постят на POST /contact напрямую, минуя вашу вёрстку. Валидация полей их не отсекает: адрес почты у них синтаксически верный, имя заполнено, сообщение — ссылка на казино. Капча решает эту задачу, но выбор конкретного механизма влияет на то, сколько живых пользователей вы потеряете на шаге отправки.
Ниже — три подхода для Laravel 11.x (то же справедливо для 10.x): скрытое поле honeypot, Google reCAPTCHA v3 и hCaptcha. У каждого своя цена в терминах UX, приватности и нагрузки на сторонний сервис. Разбираем на форме обратной связи с одним контроллером.
Очевидное решение и почему его мало
Первое, что приходит в голову — добавить в форму вопрос «сколько будет 2+2» или проверку required на все поля. Боты давно умеют и то, и другое: примитивный спам-скрипт заполняет любые видимые поля и решает арифметику по регулярке. Серьёзная защита нужна там, где форма публична и не требует авторизации: контакты, регистрация, комментарии.
Дальше — три рабочих варианта. Начинаем с самого дешёвого по нагрузке и заканчиваем самым надёжным.
Подход 1. Honeypot — скрытое поле-ловушка
Идея: добавить в форму поле, скрытое через CSS, которое живой пользователь не видит и не заполняет, а бот заполняет всё подряд. Если поле пришло непустым — отбрасываем запрос. Ноль внешних запросов, ноль зависимостей, ноль трения для пользователя.
Проще всего взять готовый пакет spatie/laravel-honeypot. Установка:
composer require spatie/laravel-honeypot
php artisan vendor:publish --provider="Spatie\Honeypot\HoneypotServiceProvider"
В Blade-шаблон формы вставляете директиву — она отрисует скрытое поле и метку времени:
<form method="POST" action="/contact">
@csrf
@honeypot
<input type="text" name="name">
<input type="email" name="email">
<textarea name="message"></textarea>
<button type="submit">Отправить</button>
</form>
На стороне маршрута защиту вешаете через middleware пакета:
use Spatie\Honeypot\ProtectAgainstSpam;
Route::post('/contact', [ContactController::class, 'store'])
->middleware(ProtectAgainstSpam::class);
Middleware проверяет два условия: скрытое поле пустое и форму отправили не слишком быстро (поле-таймштамп). Настройки — в опубликованном файле config/honeypot.php: имя поля, минимальное время заполнения, включение проверки на проде.
Цена. Honeypot ловит массовый примитивный спам и стоит пользователю ровно ничего. Но целевого бота, написанного под вашу форму, он не остановит: тот просто не трогает поле, которое вы прячете. Для контактной формы небольшого сайта этого часто достаточно, для регистрации на крупном сервисе — нет.
Подход 2. Google reCAPTCHA v3 — оценка риска без кликов
reCAPTCHA v3 не показывает пользователю пазлов. Она наблюдает за поведением на странице и возвращает оценку от 0.0 (бот) до 1.0 (человек). Вы сами решаете, с какого порога пропускать. Плюс — пользователь ничего не делает; минус — на клиент грузится скрипт Google, а решение о пороге ложится на вас.
Ключи получаете в консоли Google reCAPTCHA, тип — v3. Кладёте в .env:
RECAPTCHA_SITE_KEY=YOUR_SITE_KEY
RECAPTCHA_SECRET_KEY=YOUR_SECRET_KEY
На фронтенде подключаете скрипт и получаете токен перед отправкой формы:
<script src="https://www.google.com/recaptcha/api.js?render={{ config('services.recaptcha.site_key') }}"></script>
<script>
// Получаем токен при отправке формы и кладём его в скрытое поле
document.querySelector('form').addEventListener('submit', function (e) {
e.preventDefault();
const form = e.target;
grecaptcha.ready(function () {
grecaptcha
.execute('{{ config('services.recaptcha.site_key') }}', { action: 'contact' })
.then(function (token) {
form.querySelector('[name=recaptcha_token]').value = token;
form.submit();
});
});
});
</script>
Ключ прописываете в config/services.php, чтобы не тянуть env() напрямую из шаблона:
// config/services.php
'recaptcha' => [
'site_key' => env('RECAPTCHA_SITE_KEY'),
'secret_key' => env('RECAPTCHA_SECRET_KEY'),
],
На бэкенде проверяете токен запросом к Google. HTTP-клиент в Laravel — фасад Http:
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email',
'message' => 'required|string',
'recaptcha_token' => 'required|string',
]);
// Отправляем токен на проверку в Google
$response = Http::asForm()->post(
'https://www.google.com/recaptcha/api/siteverify',
[
'secret' => config('services.recaptcha.secret_key'),
'response' => $request->input('recaptcha_token'),
'remoteip' => $request->ip(),
]
);
$result = $response->json();
// success — прошла ли проверка, score — оценка «человечности»
if (! ($result['success'] ?? false) || ($result['score'] ?? 0) < 0.5) {
return back()->withErrors(['recaptcha' => 'Не удалось подтвердить, что вы не бот.']);
}
// ... сохранение заявки
}
Порог 0.5 — стартовая точка из документации Google, не догма. Собирайте score в лог первую неделю и смотрите распределение: если живые пользователи массово получают 0.3, порог занижайте, иначе будете резать своих.
reCAPTCHA v3 не пускает и не блокирует за вас. Она отдаёт число. Логика «с какого балла считать ботом» — ваша ответственность, и подобрать её без логов вслепую нельзя.
Цена. Пользователь не кликает, но каждый заход тянет скрипт Google и передаёт ему данные о поведении. Для проектов, где важна приватность и соответствие требованиям по персональным данным, это отдельный разговор с юристом. Плюс появляется зависимость от доступности сервиса Google.
Подход 3. hCaptcha — когда нужен видимый вызов и приватность
hCaptcha работает как классическая капча с картинками, но позиционируется как более приватная альтернатива. Интеграция на бэкенде почти идентична reCAPTCHA: получаете токен из виджета, отправляете на https://api.hcaptcha.com/siteverify тем же Http::asForm()->post() с параметрами secret и response. Отличие — пользователь видит и решает задание, поэтому спам режется жёстче, но растёт трение.
Виджет подключается скриптом https://js.hcaptcha.com/1/api.js и блоком <div class="h-captcha" data-sitekey="..."></div>; токен приходит в поле h-captcha-response. Точные имена полей и параметры ответа сверяйте в актуальной документации hCaptcha — они могут отличаться от версии к версии.
Что выбирать
| Критерий | Honeypot | reCAPTCHA v3 | hCaptcha |
|---|---|---|---|
| Действие пользователя | Нет | Нет | Решает задание |
| Внешний запрос | Нет | Да (Google) | Да (hCaptcha) |
| Защита от целевого бота | Слабая | Средняя | Сильная |
| Приватность | Полная | Данные уходят в Google | Заявлена приватной |
| Сложность | Минимальная | Средняя | Средняя |
Понятный критерий выбора:
- Контактная форма небольшого сайта, спам массовый и тупой — honeypot. Ноль трения, ставится за пять минут.
- Регистрация или форма, где важна конверсия — reCAPTCHA v3: невидима, но требует настройки порога по логам.
- Форма под целевой атакой, приватность в приоритете — hCaptcha с видимым заданием.
Комбинировать не запрещено: honeypot как первый барьер плюс reCAPTCHA v3 на подозрительные запросы снижает нагрузку на внешний сервис. Инвалидация токена и защита от повторной отправки одного и того же токена — отдельная тема, здесь её не разворачиваем.
Что ломается на практике
- Токен reCAPTCHA живёт около двух минут. Если пользователь долго заполняет форму, к моменту отправки токен протухает и
successвернётсяfalse. Получайте токен непосредственно передsubmit, а не при загрузке страницы. - Скрипт Google заблокирован у пользователя. Расширения-блокировщики режут
recaptcha/api.js, и форма молча не отправляется. Обрабатывайте случай, когдаgrecaptchaне определён. - Проверка порога на локалке. На
localhostreCAPTCHA часто отдаёт нестабильныйscore. Тестируйте на домене, добавленном в консоли Google. - Honeypot ломает автозаполнение. Браузер может подставить значение в скрытое поле, если у него неудачное имя вроде
email. Пакет spatie использует случайные имена — свою реализацию так же называйте нейтрально.
Что делать дальше
После подключения включите логирование результата проверки: для reCAPTCHA пишите score и action в лог хотя бы неделю, чтобы подобрать порог на своих данных, а не на цифре из туториала. Следите за долей отклонённых живых заявок — если она растёт, порог завышен. И держите fallback: если внешний сервис недоступен, решите заранее, пропускать заявку или ставить в очередь на ручную проверку, чтобы падение Google не превратилось в потерю лидов.
Репетитор 1—11 класс и ВУЗ: Математика и физика методом наведения на мысль, помощь с ДЗ.
Спросить за 8 ₽Источники: Google reCAPTCHA v3 — официальная документация, spatie/laravel-honeypot — репозиторий пакета
Частые вопросы
Работает ли этот код в Laravel 10?
Что делать, если reCAPTCHA всегда возвращает success = false?
Капча замедлит форму?
Можно ли обойтись без внешних сервисов вообще?
Куда положить ключи, чтобы не попали в git?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.