Как добавить ReCAPTCHA на свой сайт
Недавно столкнулся с тем, что боты поумнели настолько, что начали обходить обычную CAPTCHA на одном из сайтов, поддержкой которых я занимаюсь. Пришлось искать альтернативные решения, и выбор пал на reCAPTCHA от Google. Как выяснилось, подключить ее достаточно просто. Нужно зарегистрировать свой сайт на странице ReCAPTCHA (нужно иметь учетную запись в Google) и получить пару ключей: публичный (он будет размещаться на сайте) и секретный, который будет храниться только на сервере.
Дальше в форму, для которой нужна проверка CAPTCHA вставляем код такого вида:
Если вы все сделаете правильно, то в том месте сайта, куда вы вставили код, появится такой блок:
В нем же будет скрытое поле g-recaptcha-response, которое будет отправлено на сервер вместе с данными формы. Для проверки корректности прохождения CAPTCHA нам нужно сделать POST-запрос на сервер Google.Запрос делается на адрес https://www.google.com/recaptcha/api/siteverify, в нем в параметре secret передается секретный ключ, полученный при регистрации, а в параметре response — код ответа из поля g-recaptcha-response. В ответ возвращается JSON-объект, в котором нужно проверить поле success.
На PHP со включенной опцией allow_url_fopen код проверки будет выглядеть выглядеть так:
Если опция allow_url_fopen на сервере выключена, можно воспользоваться моей библиотекой Requests, которая делает запрос через модуль curl. В этом случае код приобретает вид:
Отмечу, что в коде применяется такой трюк: вместо полноценного парсинга JSON-объекта этот объект рассматривается как строка, в которой проверяется наличие подстроки "success": true. Делается это для двух целей: экономия ресурсов сервера (поиск подстроки в строке — значительно менее затратная операция, чем полноценный разбор JSON) и независимость от наличия на сервере модуля JSON. Это уместно в случае простых API, где полей в ответе мало, и известно, что они не будут меняться, однако в более сложных случаях лучше к таким трюкам не прибегать.
Если проанализировать плюсы и минусы этого решения, получаем следующее.
Преимущества:
Дальше в форму, для которой нужна проверка CAPTCHA вставляем код такого вида:
<script src='https://www.google.com/recaptcha/api.js'></script>Google рекомендует вставлять тег script после head, однако на самом деле это не обязательно, и можно вставить его и прямо в форму или вообще в конец страницы перед </body>. Последний вариант, пожалуй, даже предпочтительнее, так как в этом случае код будет загружаться в самом конце загрузки страницы и не будет ее замедлять.
<div class="g-recaptcha" data-sitekey="ваш-публичный-ключ"></div>
Если вы все сделаете правильно, то в том месте сайта, куда вы вставили код, появится такой блок:
В нем же будет скрытое поле g-recaptcha-response, которое будет отправлено на сервер вместе с данными формы. Для проверки корректности прохождения CAPTCHA нам нужно сделать POST-запрос на сервер Google.Запрос делается на адрес https://www.google.com/recaptcha/api/siteverify, в нем в параметре secret передается секретный ключ, полученный при регистрации, а в параметре response — код ответа из поля g-recaptcha-response. В ответ возвращается JSON-объект, в котором нужно проверить поле success.
На PHP со включенной опцией allow_url_fopen код проверки будет выглядеть выглядеть так:
$valid_captcha = false;
if (!empty($_POST['g-recaptcha-response'])) {
$postdata = http_build_query(
array(
'secret' => 'ваш-секретный-ключ',
'response' => $_POST['g-recaptcha-response']
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
$result = file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
$valid_captcha = strpos($result,'"success": true')!==false;
}
if (!valid_captcha) {
// выводим сообщение об ошибке
}
else {
// выполняем запрошенное пользователем действие
}
Если опция allow_url_fopen на сервере выключена, можно воспользоваться моей библиотекой Requests, которая делает запрос через модуль curl. В этом случае код приобретает вид:
require_once('Requests.php');
$valid_captcha = false;
if (!empty($_POST['g-recaptcha-response'])) {
$rq = new Requests();
$result = $rq->post('https://www.google.com/recaptcha/api/siteverify', array(
'secret' => 'ваш-секретный-ключ',
'response' => $_POST['g-recaptcha-response']
));
$valid_captcha = strpos($result,'"success": true')!==false;
}
if (!valid_captcha) {
// выводим сообщение об ошибке
}
else {
// выполняем запрошенное пользователем действие
}
Отмечу, что в коде применяется такой трюк: вместо полноценного парсинга JSON-объекта этот объект рассматривается как строка, в которой проверяется наличие подстроки "success": true. Делается это для двух целей: экономия ресурсов сервера (поиск подстроки в строке — значительно менее затратная операция, чем полноценный разбор JSON) и независимость от наличия на сервере модуля JSON. Это уместно в случае простых API, где полей в ответе мало, и известно, что они не будут меняться, однако в более сложных случаях лучше к таким трюкам не прибегать.
Если проанализировать плюсы и минусы этого решения, получаем следующее.
Преимущества:
- Простота добавления в любой проект
- Высокая надежность с точки зрения защиты от ботов (а кроме того, по мере роста интеллекта ботов Google может вводить дополнительные меры по защите, при этом они будут применяться сразу же, без каких-либо дополнительных мер с вашей стороны)
- Статистика по доле пользователей, прошедших CAPTCHA и некоторые возможности регулировки ее сложности.
- Критическая зависимость от внешнего сервиса: если по каким-то причинам перестанет работать ReCAPTCHA (например, очередные «ковровые блокировки» Роскомнадзора или взлом Google-аккаунта, на котором были получены публичный и приватный ключи), то станут недоступными ключевые действия на сайте (такие как регистрация или оформление заказа).
- Если с одного адреса ходит много пользователей (а это типичная ситуация для мобильных 3G-сетей и провайдеров, подключающие пользователей через NAT), reCAPTCHA потребует от пользователя довольно большого количества действий по распознаванию картинок, что вызовет его раздражение.