Защита форм от спама «невидимой» Google reCAPTCHA v3 без потери баллов по PageSpeed Insight

?v=1

Периодически возникал вопрос по защите от ботов различных форм на сайте: регистрация, авторизация, подписка на рассылку, обратная связь, комментирование и т.д.

Стандартная капча — бесполезная, ботами она проходится «на раз», а пользователям создает проблемы.

Оптимальное решение это использовать Google reCAPTCHA v2 или v3. Обе версии Google reCAPTCHA — отличный вариант. Это лучшее, что сейчас доступно на рынке из понятных и надежных решений к тому же бесплатных.

Основная проблема у обеих версий — при подключении значительно снижаются баллы по PageSpeed Insight на 20–30.
Пример reCAPTCHA v2 — требует угадывать картинки


Пример reCAPTCHA v3 — не требует от пользователя действий, в фоне анализирует его поведение
Важный для меня момент — не создавать проблемы реальным пользователям, т.к. я сам не большой любитель угадывать транспортные средства в reCAPTCHA v2, поэтому мой выбор v3.

Итак две проблемы Google reCAPTCHA v3, которые необходимо решить:

  • висящий логотип в нижнем правом углу;
  • потеря 20–30 баллов по Google PageSpeed Insight.

Висящий логотип

В лицензионном соглашении Google допускает убрать логотип, скрыв его через CSS.

.grecaptcha-badge {
	visibility: hidden;
}


Взамен под каждой формой написать «Защита от спама reCAPTCHA Конфиденциальность и Условия использования» со ссылками на соответствующие страницы Google.
Потеря баллов по Google PageSpeed Insight

При подключении javascript-файла от reCAPTCHA v3, сильно снижаются баллы по Google PageSpeed Insight. Для меня это было критично. Думаю, что это связано с анализом поведения пользователей (подобное снижение происходит при использовании вебвизора в Яндекс.Метрике).

На хорошо оптимизированных ресурсах можно потерять 20–30 баллов. Поэтому использовать её на отдельных страницах, где скорость не важна (например, контактов) можно и без модификаций. Для использования на всём сайте (например, для защиты сквозной формы авторизации или подписки на рассылку) желательно сделать модификацию.

Я придумал вариант инициализировать reCAPTCHA v3 по клику на поля формы. По умолчанию javascript-файл от reCAPTCHA v3 не загружаю, и только если пользователь поставил курсор на одно из полей формы выполняю его загрузку. Скорее всего данный метод снижает точность определения реальных пользователей, но проблем не возникало. Для моих задач данной точности хватает.

Данную методику начал применять сначала на веб-формах 1С-Битрикс, далее для сквозных форм авторизации и подписки на рассылку на сайтах без Битрикса.

Ввиду того, что 1С-Битрикс публичная CMS, расскажу в общих чертах на её примере — про методику и возможный вариант использования. Более тонкую настройку можно сделать под свои потребности.

Использование Google reCAPTCHA v3 в веб-формах 1С-Битрикс


1. Форму вызываем стандартным компонентом bitrix: form и делаем 2 дополнения:

  • Заменяем кнопку button type=submit на обычный button type=button
  • добавляем hidden поле name=g_recaptcha_response


2. Добавляем в javascript-файл сайта или компонента инициализацию reCAPTCHA при клике по полям формы (данный пример предполагает, что вы используете jQuery на сайте):

$('body').on('click','form input, form textarea', function() {
	if (typeof(grecaptcha) == 'undefined') {
		var grecaptcha_s = document.createElement('script');
		grecaptcha_s.src = 'https://www.google.com/recaptcha/api.js?render=';

		var grecaptcha_h = document.getElementsByTagName('script')[0];
	grecaptcha_h.parentNode.insertBefore(grecaptcha_s,grecaptcha_h);
	}
});


3. Добавляем отслеживание клика по кнопке button в форме. Далее внутри, используем пример описанный в документации Google. Он заполняет поле g_recaptcha_response, которое мы будет использовать на последнем шаге для валидации пользователя.

$('body').on('click','form button[name="web_form_submit"]', function() {
	grecaptcha.ready(function() {
		grecaptcha.execute('',{action: 'feedback'}).then(
			function(token) {
				$('form input[name="g_recaptcha_response"]').val(token);

				var form_obj = $('form');
				var event_obj = form_obj.get(0);

				BX.fireEvent(event_obj,'submit');	
				event_obj.submit();
			}
		);
	});
});


4. Отслеживаем event onBeforeResultAdd в init.php

Перед отправкой результатов формы делаем обращение на сервер Google с вашим , и значением из hidden поля g_recaptcha_response из формы.

В ответ получаем баллы данного пользователя:

  • 1 это точно человек
  • 0 точно робот
  • Больше 0.5 можно считать человеком
AddEventHandler("form","onBeforeResultAdd","onBeforeResultAddHandler");

function onBeforeResultAddHandler($WEB_FORM_ID,$arFields,$arrVALUES)
{
	global $APPLICATION;

	$g_recaptcha_response = $arrVALUES["g_recaptcha_response"];
	if (!empty($g_recaptcha_response))
	{
		$response = json_decode(file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=&response=".$g_recaptcha_response."&remoteip=".$_SERVER["REMOTE_ADDR"]),true);
			

		$g_recaptcha_response_check = false;

		if (($response["success"] and $response["score"] >= 0.5 and $response["action"] == 'feedback']))
		{
			$g_recaptcha_response_check = true;
		}

		if (!$g_recaptcha_response_check)
		{
			$APPLICATION->ThrowException('Не пройдена проверка Google reCAPTCHA v3.');
		}
	}
	else
	{
		$APPLICATION->ThrowException('Не пройдена проверка Google reCAPTCHA v3.');
	}
}


В заключении


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

Подобным образом можно поступить и с Google reCAPTCHA v2, инициализировать по клику на форме и просить пользователя установить галочку «Я не робот» и отгадать картинки, если потребуется. В данном случае это также сэкономит баллы по PageSpeed Insight и даст пользователю инструмент (выбирать картинки), чтобы доказать, что он не робот. Но как я уже говорил выше для меня самое важное, это не создавать пользователю преград.

© Habrahabr.ru