Перейти к содержимому
WebShield Docs

Боты регистрируются и спамят через формы

Как из своего бэкенда запрашивать у WebShield оценку каждой регистрации или заявки и отсеивать фейковые аккаунты, спам и SMS-накрутку.

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

Решение — защита форм: тег на страницах наблюдает за визитом, а ваш бэкенд в момент отправки запрашивает у нас оценку и получает вердикт. Что делать с вердиктом, решает ваш код.

Что получится: каждая регистрация или заявка получает вердикт allow, challenge или deny с причинами; боты отсеиваются, а сомнительным посетителям показывается проверка — только им, а не всем подряд. Понадобится: доступ к коду сайта — и к шаблону страниц, и к обработчику формы на сервере. Переносить домен к нам не нужно. Время: час-два вместе с выкаткой.

Услуги → Защита форм → Создать проект. В Разрешённые адреса сайта впишите схему и домен без пути — https://example.com и https://www.example.com. Вы получите ключ сайта и готовый код тега.

Для бэкенда понадобится API-токен со скоупом Защита форм: запись. Положите его в секреты приложения, рядом с паролем от базы.

В <head> всех страниц сайта, не только страницы с формой:

<script src="https://af.webshield.pro/t/v1.js?k=ВАШ_КЛЮЧ"
data-forms="#signup" async></script>

В data-forms — CSS-селекторы ваших форм через запятую. Тег сам добавит в каждую скрытое поле ws_sid — идентификатор сессии посетителя. На всех страницах тег нужен потому, что визит до формы — тоже часть оценки.

Проверка: откройте страницу с формой, в инструментах разработчика найдите в форме <input type="hidden" name="ws_sid"> — через секунду-другую у него появится значение.

В обработчике формы, до создания пользователя и отправки SMS, отправьте ws_sid к нам.

PHP:

function ws_decision(string $sid, string $event): string
{
$ch = curl_init('https://webshield.pro/api/v1/antifraud/score');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('WS_TOKEN'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'site_key' => getenv('WS_SITE_KEY'),
'session_id' => $sid,
'event' => $event,
]),
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
// Наш сбой не должен ронять вашу регистрацию.
if ($body === false || $code !== 200) {
return 'allow';
}
return json_decode($body, true)['decision'] ?? 'allow';
}
$decision = ws_decision($_POST['ws_sid'] ?? '', 'signup');

Node.js:

async function wsDecision(sid, event) {
try {
const resp = await fetch("https://webshield.pro/api/v1/antifraud/score", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ site_key: process.env.WS_SITE_KEY, session_id: sid, event }),
signal: AbortSignal.timeout(3000),
});
if (!resp.ok) return "allow";
return (await resp.json()).decision ?? "allow";
} catch {
// Наш сбой не должен ронять вашу регистрацию.
return "allow";
}
}
const decision = await wsDecision(req.body.ws_sid ?? "", "signup");

Пример на Python — в справке.

event — название действия, его придумываете вы: signup, login, contact, sms. Давайте разные имена разным формам: частота считается по каждому отдельно.

Не включайте отказы в первый же день. Неделю просто записывайте вердикт рядом с регистрацией и смотрите, кого он отсекает. Отчёт в карточке проекта покажет то же со своей стороны: долю автоматизации, причины срабатываний и последние сессии.

Когда вердиктам можно доверять, применяйте их:

if ($decision === 'deny') {
http_response_code(403);
exit('Регистрация отклонена.');
}
if ($decision === 'challenge') {
// Без немедленного отказа: подтверждение почты, ручная модерация,
// без SMS до подтверждения — что дешевле для вас и не мешает человеку.
}
// allow — регистрируем как обычно.

Самое ценное для SMS-накрутки: не отправляйте платное сообщение ни при чём, кроме allow. Для challenge подойдёт письмо на почту или проверка посетителя.

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

Пока проверка выключена, вердикт в API всё равно настоящий — переключатель влияет только на то, что видит посетитель.

  • Зарегистрируйтесь сами из обычного браузера: вердикт allow.
  • Отправьте форму из curl без ws_sid: вердикт challenge с причиной no_session — запрос мимо браузера мы без внимания не оставляем.
  • В отчёте проекта появились сессии и события.
Симптом Причина и решение
У всех подряд challenge и no_session ws_sid до бэкенда не доходит. Селектор в data-forms не совпадает с формой, или форму отправляет ваш JavaScript и не берёт скрытое поле — см. ручную привязку.
Ошибка 403 от API У токена нет скоупа Защита форм: запись или истёк его срок.
В отчёте пусто, ws_sid не заполняется Адрес страницы не входит в Разрешённые адреса сайта — проверьте схему и www.
Вторая форма на странице не защищена Тег поставлен дважды. Оставьте один и перечислите обе формы в data-forms через запятую.
Мобильное приложение получает challenge В приложении нет нашего тега, и сессии нет. Заведите для него отдельный обработчик со своей логикой.