Настройка антиспам-защиты форм 1С-Битрикс
Спам в формах — проблема не только раздражающая, но и технически дорогостоящая: засоряет CRM мусорными лидами, перегружает email-очереди, создаёт ложные срабатывания в аналитике. Стандартная CAPTCHA от Битрикс (bitrix:main.captcha) — изображение с символами — с 2020 года практически не работает: современные боты распознают её с точностью 95%+. Нужен многоуровневый подход.
Уровни защиты
Эффективная антиспам-защита — это несколько независимых уровней, каждый из которых отсеивает свой тип атаки:
- Honeypot — скрытое поле, которое заполняют только боты
- Тайминг — форма, отправленная быстрее 3 секунд после загрузки — бот
- Rate limiting — ограничение количества отправок с одного IP
- reCAPTCHA v3 / Turnstile — JS-проверка без CAPTCHA-изображений
- Проверка email — MX-запись, disposable email домены
- Проверка телефона — валидный формат, не в черном списке
Honeypot: простейший и эффективный метод
// В шаблоне формы — скрытое поле, невидимое через CSS (не display:none — это подозрительно для некоторых ботов)
?>
<div style="position:absolute;left:-9999px;top:-9999px;opacity:0;height:0;overflow:hidden">
<label for="email_confirm">Leave empty</label>
<input type="text"
id="email_confirm"
name="email_confirm"
tabindex="-1"
autocomplete="off"
value="">
</div>
<?php
Серверная проверка:
// Если поле заполнено — это бот
if (!empty($data['email_confirm'])) {
// Тихо игнорируем, не показываем ошибку боту
echo json_encode(['success' => true]);
exit;
}
Тайминг: форма не может быть отправлена мгновенно
// При рендере формы записываем timestamp в скрытое поле
$formToken = base64_encode(json_encode([
'ts' => time(),
'sessid' => bitrix_sessid(),
]));
<input type="hidden" name="form_token" value="<?= htmlspecialchars($formToken) ?>">
Серверная проверка:
$token = json_decode(base64_decode($data['form_token'] ?? ''), true);
$timeElapsed = time() - (int)($token['ts'] ?? 0);
if ($timeElapsed < 3) {
// Слишком быстро — признак бота
$this->markSpam('timing', $timeElapsed);
exit(json_encode(['success' => true])); // тихий успех для бота
}
if ($timeElapsed > 3600) {
// Форма протухла — ошибка для пользователя
exit(json_encode(['success' => false, 'error' => 'Сессия истекла. Обновите страницу.']));
}
Rate Limiter через Redis/Кеш Битрикс
namespace Local\AntiSpam;
class RateLimiter
{
private const LIMITS = [
'ip' => ['max' => 5, 'window' => 3600], // 5 форм с IP за час
'email' => ['max' => 3, 'window' => 86400], // 3 заявки с email за день
'phone' => ['max' => 2, 'window' => 86400], // 2 заявки с телефона за день
];
public function check(string $type, string $identifier): bool
{
$limit = self::LIMITS[$type] ?? ['max' => 3, 'window' => 3600];
$key = 'spam_rl_' . $type . '_' . md5($identifier);
$cache = \Bitrix\Main\Application::getInstance()->getManagedCache();
$count = (int)$cache->get($key);
if ($count >= $limit['max']) {
$this->logAttempt($type, $identifier, 'rate_limit');
return false;
}
$cache->set($key, $count + 1, $limit['window']);
return true;
}
private function logAttempt(string $type, string $identifier, string $reason): void
{
\CEventLog::Add([
'SEVERITY' => 'WARNING',
'AUDIT_TYPE_ID' => 'SPAM_BLOCKED',
'MODULE_ID' => 'local.antispam',
'DESCRIPTION' => "Blocked: type={$type}, id={$identifier}, reason={$reason}",
'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'],
]);
}
}
reCAPTCHA v3: скоринг без UX-прерывания
Google reCAPTCHA v3 не показывает CAPTCHA пользователю — она работает в фоне и возвращает score от 0 до 1 (0 = бот, 1 = человек).
Интеграция в форму:
// Подключаем reCAPTCHA v3
// <script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
async function submitForm(formData) {
const token = await grecaptcha.execute('YOUR_SITE_KEY', { action: 'callback_form' });
formData.recaptcha_token = token;
formData.recaptcha_action = 'callback_form';
// отправка...
}
Серверная верификация:
namespace Local\AntiSpam;
class RecaptchaV3Verifier
{
private string $secretKey;
private float $minScore;
public function __construct(float $minScore = 0.5)
{
$this->secretKey = \Bitrix\Main\Config\Option::get('local.antispam', 'recaptcha_secret');
$this->minScore = $minScore;
}
public function verify(string $token, string $expectedAction = ''): bool
{
$ch = curl_init('https://www.google.com/recaptcha/api/siteverify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'secret' => $this->secretKey,
'response' => $token,
'remoteip' => $_SERVER['REMOTE_ADDR'],
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
if (!($response['success'] ?? false)) {
return false;
}
// Проверяем action
if ($expectedAction && ($response['action'] ?? '') !== $expectedAction) {
return false;
}
return ($response['score'] ?? 0) >= $this->minScore;
}
}
Для российской аудитории Google reCAPTCHA может блокироваться. Альтернатива — Cloudflare Turnstile (без VPN-проблем) или Yandex SmartCaptcha.
Yandex SmartCaptcha: российская альтернатива
// Подключение
// <script src="https://captcha-api.yandex.ru/captcha.js" defer></script>
// Отображение виджета
const captchaId = window.smartCaptcha.render('captcha-container', {
sitekey : 'YOUR_SITE_KEY',
callback : (token) => { document.getElementById('smart-token').value = token; },
});
Серверная проверка:
function verifyYandexCaptcha(string $token): bool
{
$secretKey = \Bitrix\Main\Config\Option::get('local.antispam', 'yandex_captcha_secret');
$ch = curl_init('https://smartcaptcha.yandexcloud.net/validate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'secret' => $secretKey,
'token' => $token,
'ip' => $_SERVER['REMOTE_ADDR'],
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return ($result['status'] ?? '') === 'ok';
}
Проверка disposable email
Временные email-адреса (mailinator.com, guerrillamail.com и т.д.) — признак спама:
class EmailValidator
{
private const DISPOSABLE_DOMAINS_URL =
'https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/master/disposable_email_blocklist.conf';
public function isDisposable(string $email): bool
{
$domain = strtolower(substr(strrchr($email, '@'), 1));
// Кешируем список на 24 часа
$cache = \Bitrix\Main\Data\Cache::createInstance();
if (!$cache->initCache(86400, 'disposable_domains', '/antispam/')) {
$cache->startDataCache();
$list = file(self::DISPOSABLE_DOMAINS_URL, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$cache->endDataCache($list);
} else {
$list = $cache->getVars();
}
return in_array($domain, $list ?? [], true);
}
}
Состав работ
- Реализация honeypot во всех формах сайта
- Тайминг-проверка через скрытый timestamp-токен
- Rate limiter по IP, email, телефону
- Интеграция reCAPTCHA v3 или Yandex SmartCaptcha
- Проверка disposable email при регистрации и подписке
- Логирование заблокированных попыток в
CEventLog - Дашборд статистики: количество заблокированных по типу за период
Сроки: базовый набор (honeypot + тайминг + rate limit) — 3–5 дней. Полный стек со SmartCaptcha и мониторингом — 1–2 недели.







