Подсключение reCaptcha v3 на сайт Django / Bitrix

14 января 2022 г.

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

Для наглядности и понимания приведу определение данного сервиса из документации Googl:

«Google reCAPTCHA V3 - это новейший вид капчи от Google, который основан на рейтинге "человечности" пользователя в диапазоне значений от 0.1 до 0.9 и не требует от пользователя выполнения каких-либо заданий.

Подключение такой reCaptca не очень сложно. Давайте рассмотрм один из возможных примеров такого подключения с использованием ajax запросов. Для работы нам понадобятся два ключа: секретный и публичный. Для этого нужно зарегистрировать домен на сайте сайт reCaptcha v3. Тут же можно посмотреть статистику по запросам, сколько было ложных срабатываний, а сколько раз форма заполнялась человеком. Задаем константы для полученных ключей: CAPTCHA_SITE_KEY = 'публичный ключ' CAPTCHA_SECRET_KEY = 'секретный ключ''

На странице с формой необходимо подключить скрипт, который будет формировать token при отправке публичного ключа на сервер Google и подставлять этот token в нашу форму обратной связи. Далее есть некоторый различия по вызову этих констант в html шаблонах сайта, я приведу небольшие примеры: Для Bitrix, импорт этих констант не должен вызвать проблем, прописав их в init.php, они будут доступны во всем проекте.

<?
define(‘CAPTCHA_SITE_KEY’, ‘публичный ключ’);
define(‘CAPTCHA_SECRET_KEY’, ‘секретный ключ’);
?>

Для Django, эти константы можно прописать в settings.py. Для того, что бы вывести занные в html шаблоне страницы из этого файла, проще всего использовать тэги шаблона simple_tag, который будет выводить данные по имени константы. В файле template_tags.py в папке нашего приложения пропишем такой simple_tag

from django import template
from django.conf import settings

register = template.Library()


@register.simple_tag
def settings_value(name):
    return getattr(settings, name, "")

В script видно, как можно применить этот фильтр, не забудьте предварительно загрузить этот файл в html шаблон

Сам скрипт запроса для формирования token может выглядеть примерно следующим образом:

<script  src="https://www.google.com/recaptcha/api.js?onload=onloadCallbackRecap&render={% settings_value "CAPTCHA_SITE_KEY" %}" async defer></script>

<script>

    var onloadCallbackRecap = function() {
        grecaptcha.ready(function () {
            grecaptcha.execute("{% settings_value "CAPTCHA_SITE_KEY" %}", { action: 'contact_callback' }).then(function (token) {
                var recaptchaResponse = document.getElementById('recaptchaResponse');
                recaptchaResponse.value = token;
            });
        });
    };   

    setInterval(() => {
        grecaptcha.ready(reCAPTCHA_execute);
    }, 120000);

</script>

В первой строке обращаемся к google асинхронно и вешаем callback, в котором формируем token на основании публичного ключа и подставляем значение в поле формы: У данного token есть определенное время жизни, если пользователь откроет страницу с формой и оставит ее на длительное время, то token станет недействительным, однако в форме он у будет указан. Следуем продумать автоматическую смену token во времени. Для этого мы и используем setInterval. На этом с формированием token мы закончили. Мы получили ключи, на основе публичного ключа сделали token и подставили в форму. Так же нам не страшно, если token «протухнет». Далее нужно обработать отправку данных форма по ajax и получить ответ Google, насколько мы «человечны». Начнем с перехвата отправки формы. На отправку формы вешаем событие, которое прерывает это действие. Создаем ajax - запрос.

$("#our_form").on("submit", function(e){

$.ajax({
             url: "/ajax_request_form/",
            type: "POST",
            dataType: "json",
            processData : false,
            contentType : false,
            data: data,            
            success: function (data) {  
                
            }
});  

В поле «url» для Bitrix указываем путь до файла « что-то.php». Для Django нужно указать url, по которому будет обрабатываться view.

Обработка request для Bitrix:

if(!!$captcha) { // если передан код капчи
  $aContext = array(
            'http' => array(
                'proxy'           => 'tcp://10.105.0.217:3128',
                'request_fulluri' => true,
            ),
        );
        $cxContext = stream_context_create($aContext);

        $recaptcha_url = 'https://www.google.com/recaptcha/api/siteverify';
        $recaptcha_secret = RE_SEC_KEY;
        $recaptcha_response = $captcha;
        // убрали потому как отключили параметры allow_url_fopen = Off и allow_url_include = Off
        //$recaptcha = file_get_contents($recaptcha_url . '?secret=' . $recaptcha_secret . '&response=' . $recaptcha_response, false, $cxContext);        
        $recaptcha = TTKHelper::getResponseOfCapcha_3($recaptcha_response);
        $recaptcha = json_decode($recaptcha);
        $_SESSION["test"] = $recaptcha;
        if ($recaptcha->score >= 0.5) {
            $req["captcha"] = "капча пройдена";
        } else {
            $req["error"][] = "капча не пройдена";         
        }
 } 

Обработка request для Django:

pip install request - установим необходимые зависимости python файл url.py

urlpatterns = [  
    path('feedback /', AboutPage.as_view(), name='about'), 
]

файл views.py

from django.http import JsonResponse
from django.conf import settings
from .forms import *
import requests

class AboutPage(View):
    """ Обработка формы """   

    def get(self, request):
        feedback_form = FedbackAboutForm()
        return render(request, 'page/about.html', {'form': feedback_form})

    def post(self, request):
        feedback_form = FedbackAboutForm(request.POST)
        if feedback_form.is_valid():
            #feedback_form.send_email()

            #проверка капчи
            recaptcha_response = request.POST.get('captcha')
            data = {
                'secret': settings.CAPTCHA_SECRET_KEY,
                'response': recaptcha_response
            }
            r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
            recaptcha = r.json()
            if recaptcha["score"] > 0.5: // тут будет проверка на «человечность»
                response = {
                    'is_error': False,                                                  
                }  
            else:
                response = {
                    'is_error': True,   
                    'error_text': "Рекапча не пройдена",
                    'error_type': "recaptcha"                              
                } 
        else:            
            response = {
                'is_error': True,  
                'error_text': feedback_form.errors,
                'error_type': "fields"        
            }

        return JsonResponse(response)

Полезного и практичного использования!

Комментарии(0)