Битрикс и reCapcha. Боремся с роботами, а не с людьми

Что такое капча и какие с ней бывают проблемы

Что такое “капча” сегодня знает даже школьник. А вот “зачем” — хорошо знают владельцы сайтов.

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

На помощь, с девизом “Просто для людей, сложно для роботов”, спешит Google reCapthca .

Забегая вперед, скажу что мы сделали свой клевый/универсальный/не требующий программирования модуль для замены стандартной капчи на reCaptcha .

Google-капча: принцип работы

reCAPTCHA представляет из себя небольшой виджет. Для большинства пользователей он выглядит как просто поле с галочкой.

reCAPTCHA

В некоторых случаях потребуется пройти небольшое задание, чтобы доказать что Вы не робот. Например, Google может попросить Вас выбрать из списка изображения с определенным объектом, или выделить на одном изображении нужный объект:

Потребуют ли от Вас проходить такое задание или нет зависит от того, что Google знает о Вас.

Если Ваши действия в интернете похожи на человеческие (вы читаете разные сайты, авторизованы в почте, вводите поисковые запросы) - скорее всего проходить квест не потребуется.

Работа большинства капч основана на задаче распознавания текста. Роботы плюс-минус научились их разгадывать. Google reCaptcha 2.0 пошла дальше и использует задачи распознавания изображений. Пока роботы угадывают изображения сильно хуже людей.

Как подключить reCAPTHCA в Битрикс

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

Решения из MarketPlace

Маркетплейс предлагает несколько решений для подключения рекапчи. Среди них есть платные и бесплатные . Все обещают примерно одинаковую функциональность: включение и отключение рекапчи на всем сайте буквально в один клик. Нужно только зарегистрировать Ваш домен на сайте   www.google.com/recaptcha и вписать 2 полученных ключа в настройках модуля.

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

  • поддержка нескольких капч на странице,

  • капча во всплывающем окне, которое потенциально загружается по AJAX.

Как же справляются с этими задачами готовые решения Marketplace?

Мы проверили на примере пары самых популярных (по количеству установок) решений которые можно попробовать без покупки.

Модуль “ reCaptchaFree

Доступные настройки:

  • поддержка многосайтовости - можно настроить рекапчу для каждого сайта в отдельности;

  • возможность отключения рекапчи без удаления модуля. Правда здесь обнаружилась проблема - при деактивации рекапчи с помощью этой настройки  скрипты js  все равно подключались на странице.

  • настройка визуального отображения виджета и т.д.

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

Также после установки модуля потребуется отредактировать шаблон компонента, чтобы избавиться от подобных ситуаций:

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

Модуль “ Google ReCaptcha – улучшенная капча и защита от ботов

Состав настроек невелик: только ключи. Поэтому для отключения рекапчи придется удалять модуль.

Что касается работоспособности, то с обычными формами модуль справился неплохо. А вот с некоторыми компонентами в режиме Ajax вызвал ошибки.

Другие модули (например, Google reCAPTCHA | продвинутая капча ) из MarketPlace не предоставляют возможность для тестирования.

Как сделать самим

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

Кастомизация компонента и шаблона компонента

Капча выводится в шаблонах некоторых компонентов. Правильность ее ввода проверяется в компоненте. Почему так? - Потому что:

  • Так архитектурно правильно. MVC и все такое.

  • Шаблон компонента кешируется и выполняется не всегда.

Следовательно, без кастомизации компонента здесь никак не обойтись.

class GoogleReCaptcha

{

public static function getPublicKey() { return ‘your_public_key’;}

public static function getSecretKey() { return ‘your_secret_key’;}

/**

   * @return array - if validation is failed, returns an array with errors, otherwise - empty array. This format is expected by component.

   */

  public static function checkClientResponse()

  {

      $context = \Bitrix\Main\Application::getInstance()->

getContext();

      $request = $context->getRequest();

      $captchaResponse = $request->getPost("g-recaptcha-response");

      if($captchaResponse)

      {

          $url = ' https://www.google.com/recaptcha/api/siteverify ';

          $data = array('secret' => static::getSecretKey(), 'response'

=> $captchaResponse);

          $httpClient = new HttpClient();

          $response = $httpClient->post($url,$data);

          if($response)

              $response = \Bitrix\Main\Web\Json::

decode($response,true);

          if(!$response['success']) {

              return $response['error-codes'];

          }

          return array();

      }

      return array(‘no captcha response’);

  }

}


Используем компонент bitrix:main.register. В этом компоненте предусмотрена стандартная капча.

Скопируем компонент в наше пространство имен директории  /bitrix/components/. Найдем в коде компонента проверку ввода каптчи.

Фрагмент из файла  component.php:

// check captcha

   if ($arResult["USE_CAPTCHA"] == "Y")

   {

       if (!$APPLICATION->CaptchaCheckCode($_REQUEST["captcha_word"], $_REQUEST["captcha_sid"]))

           $arResult["ERRORS"][] = GetMessage("REGISTER_WRONG_CAPTCHA");

   }

В данном фрагменте заменим проверку стандартной капчи на нашу проверку рекаптчи  Google:

if ($arResult["USE_CAPTCHA"] == "Y")

   {

       $errorMessages = GoogleReCaptcha::checkClientResponse();

if( !empty($errorMessages)))

           $arResult["ERRORS"][] = $errorMessages;

   }

Затем отредактируем шаблон компонента. Заменим вывод стандартной капчи на рекапчу:

Фрагмент из файла template.php:

<div class="g-recaptcha" data-sitekey="<?=GoogleReCaptcha::getPublicKey()?>">

Изменения только компонента недостаточно для работы капчи. Также необходимо подключить скрипт для взаимодействия с сервисом. Сделать это следует в файле component_epilog.php компонента.

\Bitrix\Main\Page\Asset::getInstance()->addString(

“<script src=' https://www.google.com/recaptcha/api.js '></script>”);

В результате получим:


Подключение рекапчи с помощью JS

Можно попробовать пойти другим путем, чтобы не пришлось кастомизировать десятки компонентов. А именно:

  1. При отображении страницы в браузере найдем и подменим все bitrix-капчи на reCAPTCHA.

  2. Будем ловить заполнение форм на любой страницы (все POST-хиты). Если в запросе есть разгаданная пользователем reCAPTHCA заставим битрикс думать, что пользователь разгадал bitrix-капчу.

//Находим все битриксовые капчи

b_captcha_sid = $("[name='captcha_sid']");

if (b_captcha_sid.length > 0) {

  b_captcha_img = $(b_captcha_sid).siblings('img');

  if(b_captcha_img.length >0) {

//Убираем изображения

      $(b_captcha_img).remove();

      $(b_captcha_sid).each(function (index) {

         //Вставляем на место изображений рекапчу

          tmp = document.createElement('div');

          tmp.innerHTML = "<div class='g-recaptcha' data-sitekey='your_site_key'></div>";

          g_recaptcha = tmp.firstChild;

          g_recaptcha = (this.parentElement).

appendChild(g_recaptcha);

         //Отрисовываем виджет рекапчи

          if(typeof (grecaptcha) != "undefined") {

              grecaptcha.render(g_recaptcha,{

                  'sitekey': 'your_site_key'

              });

          }

      });

  }

}

//Скрываем все поля ввода слова капчи

b_captcha_word = $("[name='captcha_word']");

if (b_captcha_word.length > 0) {

  $(b_captcha_word).hide();

}


Компоненты на странице ничего не знают про Google капчу и при отправке формы будут проверять правильность ввода стандартной. Соответственно нам нужно симитировать ее ввод.

Данные HTTP запросов компоненты получают из суперглобальных переменных $_POST, $_GET, $_REQUEST. Для проверки капчи компонент ожидает переменные captcha_sid и captcha_word. captcha_word при отправке формы с рекапчей будет пустая. Ее мы возьмем из таблицы b_captcha.

Изменять суперглобальные переменные  нужно до отработки компонентов. Для этого можно использовать события, которые вызываются в процессе выполнения страницы,  а именно OnPageStart или OnBeforeProlog .

$context = \Bitrix\Main\Application::getInstance()-&gt;

getContext();

$request = $context->getRequest();

$captchaResponse = $request->getPost("g-recaptcha-response");

if($captchaResponse)

{

if(!\GoogleReCaptcha::checkClientResponse())

 {

$captchaSid = $request->getPost("captcha_sid");

    if($captchaSid)

    {

//Т.к. нет API, позволяющего получить слово капчи по ID, делаем запрос напрямую к БД

       $dbRes = \Bitrix\Main\Application::getConnection()->query(

"SELECT CODE FROM b_captcha WHERE id='".$captchaSid."'");

       if($res = $dbRes->fetch())

       {

          if($res['CODE'])

          {

             $_REQUEST['captcha_word'] = $_POST['captcha_word'] = $res['CODE'];

          }

       }

    }

 }

}


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

Подключение рекапчи с помощью OnEndBufferContent

Замену капчи мы можем осуществлять не только на клиентской части с помощью JS, но и на серверной. Для этого снова используем событие выполнения страницы  - OnEndBufferContent .

public static function OnEndBufferContent(&$content)

{

//Для форм загружаемых по ajax добавляем вызов скрипта рендера рекапчи

$renderScript = "";

$htmlId = "";

$context = \Bitrix\Main\Application::getInstance()->getContext();

$request = $context->getRequest();

if($request->isAjaxRequest())

 {

    $id = uniqid ('r_');

    $renderScript = "<script>renderRecaptcha('$id');</script>";

    $htmlId = 'id="'.$id.'"';

 }

//Убираем  поля для ввода слова

$content = preg_replace( '/<input[^<>]*name\s?=\s?.captcha_word.[^<>]*>/' , '' , $content );

//Все изображения заменяем на рекапчу

$content = preg_replace ( '/<img[^<>]*src\s?=\s?.\/bitrix\/tools\/captcha\.php\?(captcha_code|captcha_sid)=[^<>]*>/' , "<div class='g-recaptcha' data-sitekey=''your_site_key'' ".$htmlId."></div>".$renderScript ,  $content);

}

renderRecaptcha = function(elementId) {

if (typeof (grecaptcha) != "undefined") {

    var element = document.getElementById(elementId);

    if(element != undefined && element.childNodes.length == 0) {

       grecaptcha.render(element, {

          'sitekey': 'your_site_key'

       });

    }

 }

}

Ее следует добавить в шаблон сайта.


Дальнейшая проверка капчи осуществляется также как во втором способе - по событию OnPageStart или OnBeforeProlog .

Сообщения об ошибках

При замене капч разом на всем сайте (способы 2 и 3) нам потребуется изменить сообщение об ошибке ввода капчи. Чтобы избежать подобных ситуаций:

Все сообщения записываются в языковых переменных. Их мы можем переопределить глобально. Создадим файл /bitrix/php_interface/user_lang/ru/lang.php.

Для компонента добавления и редактирования элемента инфоблока запись в файле будет выглядеть так:

$MESS['/bitrix/components/bitrix/iblock.element.add.form/lang/ru/component.php']['IBLOCK_FORM_WRONG_CAPTCHA'] = "Не пройдена проверка от автоматического заполнения";

Выводы

Использование рекапчи Google обладает неоспоримыми преимуществами по сравнению с стандартной битриксовой капчей: жизнь пользователей сильно упрощается, а безопасность сайта не страдает.

Задача выглядит не очень сложной. Тем не менее в найденных на MarketPlace решениях она решена с огрехами. Мы исправили эту досадную ситуацию и представляем Вам наш модуль для замены капчи Битрикс на Google reCaptcha .   


Заявка на обновление, поддержку и сопровождение сайта 24x7
Иван
+7 (905) 000 00 00
info@intervolga.ru
www.site.ru
Хочу подключить услугу "поддержка 24x7"