Как добавить на сайт reCAPTCHA v3 для защиты от парсинга и спама


В этой заметке я покажу примеры кода для интеграции reCAPTCHA v3 на сайт для защиты от просмотра страницы ботами (парсинг), для защиты от автоматических действий на сайте и блокировки спама.

Документация по интеграции reCAPTCHA v3 на сайт довольно скудная и запутанная. Я пошагово покажу пример добавления reCAPTCHA v3 на сайт и объясню используемый код (PHP и JavaScript) чтобы при необходимости вы могли внести нужные вам изменения.

Причём поскольку я тоже (как и большинство других веб-мастеров) интегрирую reCAPTCHA v3 в уже готовый проект с обширным исходным кодом, то я для себя выбрал подход минимального вмешательства в уже существующий код веб-сайта. К примеру, при добавлении reCAPTCHA v3 для проверки сделанных запросов из форм, исходный код форм вообще не будет меняться — будет вставлен небольшой фрагмент JavaScript кода, добавляющий прослушивание событий и внесение необходимых изменений «на лету».

Google reCAPTCHA v3 отличается от предыдущей версии (которая по-прежнему доступна для использования) reCAPTCHA v2 тем, что от пользователя не требуется абсолютно никаких действий. То есть проверка проходит автоматически и незаметно. Благодаря такому подходу кроме привычно интеграции в формы (для отправки комментариев, обратной связи, доступа к сервису) reCAPTCHA v3 можно использовать и для защиты просмотра страниц от ботов.

Имеется ввиду следующий ситуация: пользователь запрашивает страницу, но перед показом выполняется проверка — не является ли этот пользователь ботом. Если пользователь не является человеком, то запрещаем ему показ страницы. Такой вариант, в принципе, можно реализовать и с reCAPTCHA v2, но можно быть уверенным, что увидев капчу для просмотра страницы (даже если нужно всего лишь один раз кликнуть мышкой), очень многие пользователи просто закроют вкладку браузера. Google reCAPTCHA v3 лишена этого недостатка, поскольку пользователю ничего не показывается и от него не требуются никаких действий.

Какие последствия блокировки доступа ботам к сайту

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

Во-первых, описанная техника заблокирует не только плохих ботов, но и хороших — таких как поисковых обходчиков от Google и Yandex. Это приведёт к тому, что если не будут предприняты дополнительные меры (например, разрешение доступа к сайту с IP принадлежащим Google и Yandex в обход капчи), то в конце концов сайт выпадет из индекса поисковых систем.

Во-вторых, некоторыми партнёрскими программами запрещено показывать рекламу на страницах, для которых закрыт доступ ботов (таких ботов как Mediapartners-Google и AdsBot-Google* для Google AdSense и YandexDirect для Рекламной Сети Яндекса). Если на защищаемом сайте показывается реклама, то нужно обеспечить доступ к страницам в обход капчи — поскольку эти роботы сами по себе не способны пройти тест «на человека».

При этом проверка качества ботов для доступа в обход капчи ни в коем случае не должна основываться только на User Agent клиента, поскольку его можно легко подменить.

По причине такого важного влияния блокировки доступа ботам, в этой статье рассмотрено два варианта блокировки:

  • блокировка к просмотру сайта
  • и более мягкий вариант — блокировка отправки форм

Вы сможете выбрать наиболее подходящий для вас. Либо сочетать оба приёма: полную блокировку доступа настроить, например, для страниц авторизации, и обычную блокировку — на страницах обратной связи, формах комментирования и т.д.

Где получить ключи Google reCAPTCHA v3

Использование reCAPTCHA v3 является бесплатным. Вам достаточно указать домен и выбрать reCAPTCHA v3 или v2. В этой инструкции я буду рассматривать третью версию.

Для получения ключей перейдите по ссылке: https://www.google.com/recaptcha/admin/create

Кстати, там так интересно написано:

Вы обязуетесь уведомлять посетителей сайта о наличии проверки reCAPTCHA v3, а также о том, что им необходимо соблюдать Политику конфиденциальности и Условия использования Google. Эту систему можно применять только для борьбы со спамом и другими нарушениями. Ее запрещено использовать в других целях, например для определения кредитоспособности, работоспособности, финансового статуса или страховых возможностей.

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

Впоследствии просматривать статистику, а также получить доступ к настройкам вы сможете со страницы https://www.google.com/recaptcha/admin.

Принципы работы reCAPTCHA v3

Первоначальный этап оценки пользователя (бот или человек) осуществляется исключительно средствами JavaScript. То есть боты без поддержки JavaScript отсеиваются уже на этом этапе. Кстати, видимо, в статистику запросов эти боты также не попадают.


Во время своей работы reCAPTCHA v3 собирает данные о взаимодействии с сайтом и формирует длинную строку — токен.

Этот токен нужно передать на сервер, обслуживающий сайт, и уже сервер с применением секретного ключа должен сделать запрос к сервису reCAPTCHA v3. Ответ будет иметь вероятностный характер — будет прислано число в диапазоне от 0 (бот) до 1 (человек). Вам самим нужно решить, какой порог является проходным для данного сайта.

Исходя из этой информации сервер должен принять решение — обрабатывать ли полученный от пользователя запрос (например, показать ли ему страницу, принять ли присланные из формы данные и т.д.).

Пример на PHP для включения reCAPTCHA v3

Мой вариант реализации состоит из двух фрагментов PHP кода. Первый лучше расположить в начале файла. Второй фрагмент нужно расположить так, чтобы выводимый им HTML находился ближе к концу исходного кода вашего сайта. Причём вам необязательно делать это с помощью PHP — вы можете вставить этот фрагмент другим образом — только в этом случае обратите внимание, что там экранированы одинарные кавычки — не забудьте отменить экранирование (убрать обратные слэши).

Прежде чем показать код (в который я также вставил много комментариев), начну с объяснения принципа работы. В самом начале делается проверка — есть ли у пользователя токен. Если нет, то вместо показа пользователю страницы сайта, выводится HTML/JavaScript код, который только получает токен и сразу же возвращает пользователя на индексную страницу (все GET запросы сохраняются, но к ним добавляется ещё одна переменная — token).

Затем вновь проверяется — есть ли у пользователя токен, если уже есть, то делается запрос к сервису reCAPTCHA v3. Если ответ положительный (это человек), то код завершает свою работу — передаётся управление основному коду сайта. Если ответ отрицательный (это бот), то код обрывает последующую обработку этого запроса — то есть немедленно останавливает работу и не передаёт управление основному коду сайта.

Первый фрагмент кода отвечает и за проверку ботов при доступе к сайту, и за проверку ботов при отправке форм.

Первый фрагмент:

<?php
$blockPageAccess = 0;
$blockFormAccess = 1;
$checked = 0;

// Функция отправки запроса на сервер Google reCAPTCHA
function sendRequestToCaptchaServer($captcha) {
    global $checked;

    // Здесь секретный ключ
    $secretKey = "ЗДЕСЬ СЕКРЕТНЫЙ КЛЮЧ";
    // Формируем запрос и отправляем полученый токен на сервер проверки
    $url = 'https://www.google.com/recaptcha/api/siteverify';
    $data = array('secret' => $secretKey, 'response' => $captcha);

    $options = array(
        'http' => array(
            'header' => "Content-type: application/x-www-form-urlencoded\r\n",
            'method' => 'POST',
            'content' => http_build_query($data)
        )
    );
    $context = stream_context_create($options);

    // Запрос к серверу google.com/recaptcha и отлов ошибок
    set_error_handler(
            function ($severity, $message, $file, $line) {
                throw new ErrorException($message, $severity, $severity, $file, $line);
            }
    );

    try {
        $response = file_get_contents($url, false, $context);
    } catch (Exception $e) {
        echo $e->getMessage();
    }

    restore_error_handler();

//    $response = file_get_contents($url, false, $context);
    $responseKeys = json_decode($response, true);
    // От сервера мы получаем ответ о набранных "очках" - от 0 до 1.
    // 1 - значит это точно человек, а 0 - это точно бот
    // Вы можете установить любой порог "прохождения". Я использую 0.5
    if ($responseKeys["success"] AND $responseKeys["score"] > 0.5 AND $responseKeys["action"] == 'homepage') {
        $checked = 1;
        // Если это человек, то просто ничего не делаем
    } else {
        // А если это бот, то завершаем работу. Перед завершением можно показать боту какое-нибудь сообщение.
        exit;
    }
}

// Инициализируем переменную
$captcha = '';
// Проверяем, имеется ли токен и присваеваем его значение переменной
if (isset($_GET["token"])) {
    $captcha = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
} elseif (isset($_POST["token"])) {
    $captcha = filter_input(INPUT_POST, 'token', FILTER_SANITIZE_STRING);
}

// Этот раздел срабатывает только если включена блокировка ботов к страницам
if ($blockPageAccess) {
    // Проверяем, является ли значение пустым
    if (!$captcha) {
        // Если токен отсутствует, значит нужно показать страницу получения токена
        // У первоначального запроса могут быть GET параметры - собираем их, чтобы передать конечной странице
        $get = '';
        foreach ($_GET as $key => $value) {
            $get = $get . "&$key=$value";
        }
        // Выводим код получения токена
        echo '
<!DOCTYPE html>

<html>
    <head>
        <title>Are you a human being?</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://www.google.com/recaptcha/api.js?render=ЗДЕСЬ КЛЮЧ САЙТА"></script>
    </head>
    <body>
        <script>
            grecaptcha.ready(function () {
                grecaptcha.execute(\'ЗДЕСЬ КЛЮЧ САЙТА\', {action: \'homepage\'}).then(function (token) {
                    //alert(token)
                    window.location.replace("?token=" + token + "' . $get . '");
                });
            });
        </script>
    </body>
</html>
';
        // Больше никаких дел нет - отключаемся. Теперь пользователь придёт снова, но уже с токеном
        exit;
    }
    // Если же токен всё-таки прислан, то инициируем запрос к серверу.
    sendRequestToCaptchaServer($captcha);
}

// Этот раздел срабатывает, если нужно проверять запросы от форм.
// Причём если включена проверка ботов при доступе к страницам, значит токен уже использован
// для проверки и больше её делать не имеет смысла.
// В любом случае, второй раз использовать тот же самый токен невозможно.
if ($blockFormAccess AND ! $checked) {
    // Если в массиве $_POST больше чем ноль значений, значит имеет место отправка из формы.
    // В противном случае нам нечего делать.
    if (count($_POST) > 0) {
        if (!$captcha) {
            // Если капча пустая, то завершаем работу.
            die('Ваш запрос не принят.');
        } else {
            // Если же токен всё-таки прислан, то инициируем запрос к серверу.
            sendRequestToCaptchaServer($captcha);
        }
    }
}

Обратите внимание на переменные:


$blockPageAccess = 0;
$blockFormAccess = 1;

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

Второй фрагмент:

<?php
if ($blockFormAccess) {
    echo '
        <script src="https://www.google.com/recaptcha/api.js?render=ЗДЕСЬ КЛЮЧ САЙТА"></script>
        <script>
            document.forms[0].addEventListener(\'submit\', function (evt) {
                evt.preventDefault();
                grecaptcha.ready(function () {
                    grecaptcha.execute(\'ЗДЕСЬ КЛЮЧ САЙТА\', {action: \'homepage\'}).then(function (token) {
                        var el = document.createElement("input");
                        el.type = "hidden";
                        el.name = "token";
                        el.value = token;
                        document.forms[0].appendChild(el);
                        document.forms[0].submit();
                    });
                });
            })
        </script>';
}
?>

Этот код нужен только если включена проверка ботов при отправке форм. Значение этого кода в том, что перед каждой отправкой формы к ней добавляется токен. Сам токен получается при отправке формы — при этом между нажатием на кнопку «Отправить» и самой отправкой не происходит дополнительной задержки.

Это чистый JavaScript без использования jQuery. Обратите внимание, как я обращаюсь к форме:

document.forms[0]

Дело в том, что у меня формы без имени и без идентификатора. Причём уникальная форма на каждой странице сайта, которых больше сотни. Благо на каждой странице форма только одна, поэтому я обращаюсь к ней по порядковому номеру. Вы можете отредактировать это под свои условия.

Не забудьте установить свои собственные ключи:


  • в первом фрагменте нужно установить приватный ключ и два раза ключ сайта (в выводимом HTML/JavaScript коде)
  • во втором фрагменте дважды нужно установить только ключ сайта — он также окажется в предназначенном для пользователя HTML/JavaScript

Официальная документация Google reCAPTCHA v3

Официальную информацию и инструкции вы найдёте на страницах:

Как это часто бывает с официальной документацией — на её основе невозможно ничего понять и невозможно что-либо настроить до рабочего состояния…

Самую важную информацию о реализации reCAPTCHA я позаимствовал из этой статьи:

При этом та инструкция содержит критическую логическую ошибку — для принятия решения используется присланное поле success. Но дело в том, что данное поле только говорит о том, являлся ли присланный токен верным токеном для данного сайта — о том, бот это или не бот, данное поле никак не сообщает. Настоящее значение, на которое нужно ориентироваться, это score. О нём чуть позже. То есть если в своей проверке использовать success, то даже явные боты, которые, может быть, набрали 0 очков, но которые сумели просто получить токен, будут успешно проходить проверку.

Тем не менее официальная документация имеет несколько познавательных фактов о reCAPTCHA — рассмотрим их.

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

Array 
( 
	[success] => 1 
	[challenge_ts] => 2019-05-28T15:39:16Z 
	[hostname] => suip.biz 
	[score] => 0.9 
	[action] => homepage 
)

Значение полей следующее:

{
  "success": true|false,      // был ли этот запрос валидным токеном reCAPTCHA для вашего сайта
  "score": число              // очки для этого запроса (0.0 - 1.0)
  "action": строка            // имя действия для этого запроса (важно для верификации)
  "challenge_ts": timestamp,  // временная метка вызова загрузки (ISO формат yyyy-MM-dd'T'HH:mm:ssZZ)
  "hostname": строка,         // имя хоста сайта, где была выполнена reCAPTCHA
  "error-codes": [...]        // опционально (коды ошибок)
}

reCAPTCHA v3 без взаимодействия с пользователем возвращает очки для каждого запроса. Эти очки основываются на взаимодействиях с вашим сайтом и дают вам возможность принять решение на их основе.

Ограничения токена

Каждый токен ответа пользователя reCAPTCHA является действительным в течении двух минут и может быть верифицирован только один раз (для предотвращения атак повторного воспроизведения (replay attacks)). Если вам нужен новый токен, то перезапустите верификацию reCAPTCHA.

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

Размещение на вашем сайте

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

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

Интерпретация очков


reCAPTCHA v3 возвращает очки (1.0 очень вероятно хорошее взаимодействие, 0.0 весьма вероятно бот). Основываясь на этих очках, вы можете предпринять различные действия в контексте вашего сайта. Каждый сайт отличается от других, но ниже несколько примеров, как сайты используют очки. Как примеры ниже, для лучшей защиты своего сайта выполняйте действия «за сценой» вместо блокировки трафика.

Случай использования Рекомендация
homepage Наблюдайте за полной картиной в вашей панели администратора: сколько из пришедших это пользователи, а сколько разного рода парсеры
login При низком показатели очков, требуйте 2-факторную аутентификацию или верификацию по почте для предотвращения атака связанных с учётными данными
social Отправляйте комментарии от пользователей с подозрением на ботов на модерацию, ограничьте для них количество безответных запросов в друзья
e-commerce Давайте приоритет реальным покупателям и выявляйте запросы, которые могут оказаться ненастоящими

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

Заключение

Этот код я писал под конкретные особенности моего сайта. Вполне возможно, что это же самое можно было сделать более изящно. Но, главные его достоинства:

  • он работает
  • требуется только вставить эти фрагменты — не нужно исправлять уже существующий код. Даже не нужно присваивать форме имя или идентификатор — если у вас их нет
  • в случае необходимости можно отключить работу кода, установив значения переменных на нули — не нужно выполнять более глубокое редактирование

На самом деле, есть место для улучшений: например, в приведённой реализации каждый поступивший от пользователя запрос проверяется. Можно, например, после первой проверки сохранять на сервере на некоторое время одобренный IP адрес и допускать к сайту без проверок. Либо можно генерировать уникальный маркер и сохранять в кукиз пользователя и в базе данных на сервере, сделав этот маркер действительным, например, на 10 минут.

При установке полной проверки доступа можно добавить функцию для проверки IP по WHOIS и допуска к сайту без капчи IP принадлежащих Google и Яндекс — чтобы поисковые роботы могли продолжать сканировать сайт.


Рекомендуется Вам:

3 комментария to Как добавить на сайт reCAPTCHA v3 для защиты от парсинга и спама

  1. Alex:

    Добрый день.

    Подскажите — как реализовать вариант 1, т.е. "Наблюдайте за полной картиной в вашей панели администратора: сколько из пришедших это пользователи, а сколько разного рода парсеры" на лендинге?

    Спасибо.

    • Alexey:

      Приветствую!

      Насколько я понимаю, «случаи использования» — это подсказки для веб-мастера, что ещё можно делать кроме блокировок. Вариант «Наблюдайте за полной картиной в вашей панели администратора…» означает, что проверяются все, но никаких санкций в отношении ботов не следует.

      То есть нужно включить проверку каждого пришедшего посетителя — в результате в статистике reCAPTCHA v3 вы увидите, сколько ботов, а сколько реальных людей.

      Причём необязательно предпринимать какие-либо действия — то есть для сбора статистики, ботов необязательно блокировать. Если нужна только статистика (без блокировки), то лучше делать проверку без перезагрузки страницы: после полной загрузки сайта в JavaScript вызывается функция генерации токена и с помощью AJAX этот токен отправляется на сервер reCAPTCHA v3.

  2. Максим:

    Здраствуйте! Подскажите куда нужно вставлять данный код чтобы все работало? И нужно ли там что то менять? Использую opencart 3. Заранее спасибо за помощь!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *