Капча наказывает посетителя за чужую вину: человек разгадывает картинку, а бот с арендованным прокси проходит её за деньги. CF7 Spam Checker Pro 4.1.1 идёт другим путём — защита формы CF7 строится из слоёв, которые идут от бесплатных локальных проверок к платным внешним, и только в том случае, если отправка всё ещё выглядит чистой. Ниже — что именно проверяется, как устроена экономия на API и моделях, что показал прогон всех файлов плагина и на чём спотыкаются при настройке.

contact form 7 llm spam checker cover

TL;DR: что это и как проверить

  1. Что это. Плагин для Contact Form 7: двенадцать слоёв проверки плюс валидация языка в полях имени.
  2. Порядок важен. Сначала локальные проверки (бан, тайминг, honeypot, UA, частота, SQLi, XSS, ссылки, слова), потом внешние (страна, AbuseIPDB), и последним — модель.
  3. Провайдеров одиннадцать. DeepSeek, OpenAI, Qwen, Claude, Gemini, Groq, Mistral, OpenRouter, Grok и любые совместимые точки через два протокола.
  4. Реестр с доказательствами. У каждого вердикта сохранены результаты проверок, поэтому ложное срабатывание разбирается в один клик.
  5. Проверка. Распаковать архив, php -l по всем файлам, установить на тестовый сайт с CF7.
unzip contact-form-7-spam-checker-4.1.1.zip -d wp-content/plugins/
php -l wp-content/plugins/contact-form-7-spam-checker/contact-form-7-spam-checker.php

Проблема, которую это решает

Спам в формах 2026 года — не «купите виагру» капсом. Это отправки от автоматизированных агентов, которые читают форму, заполняют её правдоподобными данными и приходят с адресов, которые через минуту уже не используются. Ни одна одиночная проверка такое не ловит.

Honeypot без тайминга обходится: бот заполняет скрытое поле, но иногда его и не заполняет — просто отправляет форму с правильными полями. Тайминг без honeypot ловится ботом, который умеет ждать. Частотный лимит не помогает против распределённых отправок с сотни адресов. Подписи SQLi и XSS бесполезны, когда в форму пишут осмысленный текст с одной ссылкой. А репутация IP бессильна, если бот пришёл с чистого адреса домашнего провайдера.

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

Что такое CF7 Spam Checker Pro

flowchart TB
  SUB["отправка формы CF7"] --> WL{"IP в белом списке?"}
  WL -- да --> OK["пропустить"]
  WL -- нет --> LOC["локальные проверки: бан, время, honeypot, UA, частота, SQLi, XSS, ссылки, слова"]
  LOC -- сработало --> BAN["блокировка и запись в реестр"]
  LOC -- чисто --> API["внешние проверки: страна, AbuseIPDB"]
  API -- сработало --> BAN
  API -- чисто --> LLM["LLM: вердикт SPAM или CLEAN"]
  LLM -- SPAM --> BAN
  LLM -- CLEAN --> OK
Свойство Значение
Тип плагин WordPress для Contact Form 7
Версия в разборе 4.1.1 (патч: исправления аудита, без новых возможностей)
Требования WordPress 6.0+, PHP 8.3+, Contact Form 7 5.7+
Лицензия GPL-2.0-or-later
Слоёв проверки 12 плюс валидация языка
Провайдеров LLM 11
Хранение собственные таблицы: реестр спама, IP-список, кеш ответов, настройки

Название в шапке плагина — «CF7 Spam Checker Pro», текстовый домен — contact-form-7-spam-checker, версия в коде CF7SEC_VERSION = 4.1.1, схема базы CF7SEC_DB_VERSION = 400.

Возможности

Слои проверки

Первые десять слоёв работают локально и ничего не стоят: белый список IP, бан-лист, тайминг заполнения, honeypot, разбор user-agent, частотный лимит, подписи SQLi, подписи XSS, ограничение числа ссылок и чёрный список слов. Затем идут два платных: фильтр по стране и AbuseIPDB. Замыкает цепочку модель.

Важная деталь в тайминге: время измеряется на клиенте монотонным таймером, поэтому не ломается ни от сдвига часов, ни от кеширования страницы. Если JavaScript не сработал, есть запасной вариант — серверная метка времени с допуском на расхождение.

Про user-agent стоит сказать отдельно: список включает больше шестидесяти признаков автоматизации, но с подавлением ложных срабатываний для настоящих браузерных имён. Без этого фильтр отсекал бы часть живых посетителей, и владелец сайта узнал бы об этом из жалоб, а не из логов.

Вердикт модели

Что Как работает
Провайдеры DeepSeek, OpenAI, Qwen, Anthropic, Gemini, Groq, Mistral, OpenRouter, xAI, плюс свои совместимые точки
Протоколы OpenAI-совместимые chat completions и Anthropic Messages
Ответ строго SPAM или CLEAN
Ключи отдельный на провайдера, маскируются в интерфейсе
Модель свободный идентификатор с подсказками
Адрес переопределение base URL для прокси и региональных точек
Ошибка политика fail-open или fail-closed на выбор
Проверка связи встроенный тестер подключения

Свободный идентификатор модели — правильное решение: список моделей меняется быстрее, чем выходят версии плагинов.

Реестр и управление IP

flowchart LR
  V["вердикт по отправке"] --> REG["реестр: проверки, данные, UA, реферер"]
  REG --> STRIKE{"порог strikes?"}
  STRIKE -- да --> PERM["бан, при повторе постоянный"]
  STRIKE -- нет --> WATCH["только запись"]
  REG --> EXP["CSV и срок хранения"]
  REG --> NOTIFY["письмо о волне спама"]
Что Как работает
Реестр поиск по вердиктам, полные доказательства: результаты проверок, очищенные данные, UA, реферер
Экспорт CSV
Хранение настраиваемый срок, готовность к требованиям по персональным данным
IP-таблица баны и белый список в одном месте
Эскалация N-й бан становится постоянным
Ручной бан приватные и зарезервированные диапазоны отклоняются
Массовые операции удаление пакетом, выгрузка CSV
Справка по адресу запрос к AbuseIPDB прямо из строки таблицы

Эскалация strikes — то, чего обычно не хватает: один и тот же адрес возвращается, и вместо бесконечных временных банов он получает постоянный.

Репутация и отчёты

Что Как работает
Пороги AbuseIPDB три независимых: процент уверенности, общее число отчётов, отчёты категории «почтовый спам»
Кеш в базе, TTL настраивается
Квота видно по заголовкам ответа API
Автоотчёт подтверждённый спамер отправляется в сообщество, категория 10
Уведомления письма с ограничением частоты: баны, волны спама, ошибки интеграций

Три порога вместо одного — практично: адрес с двадцатью отчётами и уверенностью 90 % и адрес с двумя отчётами, но оба «почтовый спам», — разные случаи.

Интерфейс и эксплуатация

Что Как работает
Оформление Tailwind-подобная система, тёмная, светлая и системная тема
Экран адаптивно до 360 пикселей
Внешние ресурсы ни одного CDN, всё лежит локально
Языки английский, русский, китайский, немецкий
Экспорт настроек JSON, импорт обратно
Диагностика страница состояния, просмотр журнала отладки
Обслуживание cron раз в сутки плюс кнопка ручного запуска
Удаление аккуратный uninstall.php
REST пространство cf7sec/v1 с nonce и проверкой прав manage_options

Отсутствие CDN — не мелочь: страница настроек безопасности не должна зависеть от доступности чужого сервера, а в закрытых сетях она вообще не загрузится без локальных ресурсов.

Как это работает

Три правила, сформулированные в документации, объясняют устройство лучше любого описания.

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

Второе: внешние проверки — последними. Пока отправка не прошла локальные слои, ни AbuseIPDB, ни модель не вызываются. Это экономит квоту API и токены, а при большом потоке спама разница ощутима.

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

Замеры и цифры

Проверено 11.11.2026, двумя проверками.

Что проверено Значение Как
Архив релиза 1 802 159 байт, SHA-256 adf6a62b…3408f скачивание релиза и подсчёт хеша
Размер дерева после распаковки 2,6 МБ du
PHP-файлов 60 find
Строк PHP 7 751 подсчёт по всем файлам
Проверка синтаксиса php -l по всем 60 файлам — ошибок нет прогон в Git Bash, PHP 8.5.0
Крупнейшие файлы RestController 23 494 Б, Settings 20 259 Б, шаблон настроек 17 656 Б, SpamPipeline 15 493 Б сортировка по размеру
Структура src/Admin, src/Security, src/Services, src/Storage, src/Support список каталогов

Вторая проверка — живой сайт. На этом блоге 24 плагина, и среди них нет Contact Form 7 — значит, и этот плагин здесь не установлен. Проверять его работу на боевом сайте без формы бессмысленно: нужен стенд с CF7.

Что проверено на живом хосте Значение
Плагинов на сайте 24
Contact Form 7 установлен нет
Этот плагин установлен нет
Репозиторий и страница релиза HTTP 200
CF7 Spam Checker Pro 4.1.1: файлы, синтаксис и состояние сайта
CF7 Spam Checker Pro 4.1.1: файлы, синтаксис и состояние сайта

Из чисел видно две вещи. Первая: 7 751 строк в 60 файлах при аккуратном разделении на слои — размер, который реально читается: ядро проверок лежит в SpamPipeline, админка отдельно, хранилище отдельно. Вторая: php -l по всем файлам чист, то есть архив релиза собирается из синтаксически целого кода — это минимальная, но обязательная проверка для плагина, который ставится на живой сайт.

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

Сильные стороны продукта

  • Слоёв много, природа разная. Одновременное срабатывание ловит и ботов, и людей с плохими намерениями.
  • Экономия на внешних вызовах. Платные проверки включаются только после локальных.
  • Форма не падает. Внутренняя ошибка пропускает отправку, а не ломает сайт.
  • Доказательства в реестре. Ложное срабатывание видно по шагам, а не «по ощущению».
  • Одиннадцать провайдеров. Нет привязки к одному поставщику модели.
  • Политика ошибки на выбор. fail-open для доступности, fail-closed для строгости.
  • Эскалация вместо вечных банов. Повторные адреса получают постоянный бан, случайные — временный.
  • Ноль внешних ресурсов в интерфейсе. Админка работает в закрытой сети.

Установка

Шаг Что сделать
1 скачать архив релиза и сверить хеш
2 распаковать в каталог плагинов
3 активировать в админке
4 проверить требования: WordPress 6.0+, PHP 8.3+, CF7 5.7+
5 открыть страницу настроек и включить локальные слои
6 настроить AbuseIPDB и провайдера модели, если нужны
7 отправить тестовую заявку и посмотреть вердикт в реестре

Первым делом стоит включить именно локальные слои: они бесплатны и закрывают основную массу ботов. Внешние проверки — второй шаг, когда видно, что локальные справляются не полностью.

Настройка

flowchart TD
  SET["настройки плагина"] --> AB["AbuseIPDB: три порога и кеш ответов"]
  SET --> GW["шлюз LLM: 11 провайдеров, два протокола"]
  GW --> POL["политика ошибки: fail-open или fail-closed"]
  AB --> AUTO["автоотчёт о подтверждённом спаме"]
  POL --> REG2["запись в реестр при ошибке"]
Что настраивать На что влияет
Чёрный список слов мгновенная блокировка по тексту, работает без внешних вызовов
Максимум ссылок в поле отсекает типовые спам-вставки
Частотный лимит окно 60 секунд на адрес
Постоянный бан после N нарушений эскалация strikes
Пороги AbuseIPDB три независимых условия
TTL кеша ответов баланс между свежестью и квотой
Провайдер и модель качество семантической проверки
Политика при ошибке что делать, если модель недоступна
Автобан по вердикту SPAM автоматика против волн спама
Уведомления частота писем о волнах и банах

Отдельно стоит подумать про fail-open и fail-closed. Первый вариант означает, что при недоступности модели заявка пройдёт — форма работает всегда. Второй блокирует отправку при ошибке — строже, но при сбое провайдера вы теряете обращения клиентов. Для формы обратной связи на сайте услуг разумнее первый; для формы с ограниченным доступом — второй.

Что изменилось в 4.1.1

Что Суть
B1 проверка моделью оказалась мёртвым кодом при схеме настроек v2 — все чтения переведены на llm.*
B2 обновление 4.0 → 4.1 стирало перенесённый ключ API и флаг включения — миграция теперь идёт до снимка настроек
M1–M12 правки оформления, убрана шапка Update URI, безопасный доступ к переданным данным, имена полей honeypot с солью HMAC
L1–L10 мелкие правки, включая описание риска подмены адреса при общем прокси
Добавлено CI на PHP 8.3/8.4/8.5: линт, smoke, проверка путей настроек, сборка ресурсов, гварды обновления и ссылок
Переводы 396 строк, 100 % для русского, китайского и немецкого

Два первых пункта — хорошая иллюстрация того, зачем нужны smoke-проверки: обе ошибки не ломали сайт, они делали защиту тихо неработающей. Первая выключала целый слой, вторая стирала ключ при обновлении.

Почему порядок слоёв — это про деньги

Соблазн проверять моделью каждую заявку понятен: семантическая проверка выглядит самой умной. На практике это две проблемы сразу.

Первая — стоимость. Каждая заявка — это запрос к платному API, и на сайте с сотней обращений в неделю разница между «моделью проверяется всё» и «моделью проверяется то, что прошло локальные слои» видна в счёте. Спам в форме обычно идёт волнами: десятки отправок за час, и все они одинаково бессмысленны для модели.

Вторая — задержка. Посетитель, нажавший «отправить», ждёт ответа; если в цепочке два внешних вызова по секунде каждый, форма начинает «тупить». Локальные проверки занимают миллисекунды, а внешние — секунды, и это надо тратить только там, где они что-то решают.

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

Третье следствие — реестр. При такой схеме всегда видно, какой слой сработал первым, а какой уже не вызывался. Именно поэтому доказательства хранятся по каждому вердикту, а не только итоговое «спам или нет».

Что делать при ложном срабатывании

Ложное срабатывание — не гипотетическая ситуация, а нормальная часть работы антиспама. Важно, чтобы его разбор занимал минуты, а не часы переписки.

Порядок такой. Открыть запись в реестре и посмотреть, какой слой вынес вердикт. Если это чёрный список слов — проверить, не попало ли в него слово, которое встречается в обычной речи. Если honeypot — убедиться, что поле не заполняет автозаполнение браузера. Если тайминг — проверить, не стоит ли на форме агрессивный кеш, из-за которого клиентский таймер стартует раньше времени. Если модель — прочитать текст заявки и решить, ошиблась ли она по сути.

Дальше действие либо точечное (убрать слово, поправить порог), либо системное (пересмотреть список признаков). И то и другое лучше делать после двух-трёх случаев: одиночное срабатывание часто оказывается случайным совпадением.

Отдельно про белый список: если клиент регулярно попадает под фильтр, его адрес стоит внести в белый список и закрыть вопрос. Это быстрее, чем обучать фильтры на исключениях.

Подводные камни

  • Слой, который «включён», может не работать. Именно это случилось в 4.0 с проверкой моделью: настройки читались по старой схеме. После обновления стоит отправить тестовую заявку и убедиться, что вердикт появился в реестре.
  • Обновление со сбросом ключа. В 4.1 ключ модели терялся при миграции; в 4.1.1 исправлено, но проверять после обновления всё равно нужно.
  • Honeypot без тайминга слабее. Скрытое поле обходится ботом, который его просто не заполняет; смысл в комбинации слоёв.
  • Тайминг требует JavaScript. Если скрипт не загрузился, работает серверный вариант с допуском — но он грубее.
  • Общий прокси искажает адрес. Если сайт за общим прокси, все посетители выглядят одним адресом; в документации риск описан, в настройках его не отключить.
  • Квота AbuseIPDB не бесконечна. Три порога и кеш как раз для экономии; без кеша при потоке заявок квота кончится.
  • Модель стоит денег. fail-open экономит не только доступность, но и бюджет: при сбое провайдера обращения проходят без проверки моделью.
  • Автобан по вердикту — обоюдоострый. При ложном срабатывании модели IP уходит в бан автоматически; политика strikes должна быть разумной.
  • Реестр хранит данные отправок. Срок хранения настраивается, и его стоит выставить осознанно: это персональные данные посетителей.
  • Плагин не из стандартной поставки. Установка — загрузка архива; обновление вручную, обновлений «из коробки» не будет.
  • Требуется PHP 8.3+. На 8.2 плагин не заработает: используются readonly-свойства, перечисления и строгие типы.

Чек-лист

  • [ ] Проверить требования: WordPress 6.0+, PHP 8.3+, CF7 5.7+.
  • [ ] Скачать архив и сверить SHA-256.
  • [ ] Распаковать в каталог плагинов и активировать.
  • [ ] Включить локальные слои: honeypot, тайминг, частотный лимит, чёрный список слов.
  • [ ] Отправить тестовую заявку и найти вердикт в реестре.
  • [ ] Настроить AbuseIPDB: ключ, три порога, TTL кеша.
  • [ ] Подключить провайдера модели и проверить соединение встроенным тестером.
  • [ ] Выбрать политику при ошибке: fail-open или fail-closed.
  • [ ] Задать срок хранения записей реестра.
  • [ ] Настроить уведомления и проверить, что письма приходят.

FAQ

Нужна ли капча вместе с этим плагином?

Нет, и в этом смысл: слои проверки работают без заданий для посетителя. Капча остаётся крайним вариантом, если сайт атакуют целенаправленно.

Сколько стоит проверка моделью?

Зависит от провайдера и модели; в плагине есть только политика вызова — внешние проверки идут последними, поэтому платят за отправки, которые уже прошли локальные слои.

Что будет, если провайдер модели недоступен?

Зависит от настройки: fail-open пропустит заявку, fail-closed заблокирует. Ошибка попадёт в реестр.

Куда пишутся заблокированные заявки?

В реестр спама: результаты всех проверок, очищенные данные, user-agent и реферер. Экспорт в CSV и настраиваемый срок хранения.

Можно ли банить по стране?

Да, через данные AbuseIPDB. Это внешняя проверка, поэтому она идёт после локальных.

Работает ли без ключа модели?

Да. Локальные слои, AbuseIPDB и фильтр по стране работают независимо; модель — дополнительный семантический слой.

Итог

CF7 Spam Checker Pro 4.1.1 — плагин, который решает задачу правильной декомпозицией: двенадцать слоёв разной природы, дешёвые проверки впереди, дорогие — позади, и реестр с доказательствами для каждого вердикта. Проверка архива подтвердила базовое: 60 файлов, 7 751 строка, php -l чист по всем файлам, структура разделена на админку, безопасность, сервисы и хранилище. Проверить поведение на живом сайте в этом прогоне не удалось — на блоге нет Contact Form 7, а ставить форму и плагин ради статьи я не стал. История 4.1.1 заодно объясняет, зачем нужны smoke-проверки: обе блокирующие ошибки не ломали сайт, а тихо выключали защиту.

Цитата: Хорошая защита формы не спрашивает у человека, робот ли он, — она смотрит на то, как он себя вёл.

Связанные материалы

LLM Summary

  • Тема: CF7 Spam Checker Pro 4.1.1 — плагин защиты формы Contact Form 7: 12 слоёв проверки плюс валидация языка, реестр вердиктов, управление IP и оценка моделью.
  • Порядок слоёв: белый список → бан-лист → тайминг → honeypot → user-agent → частотный лимит → SQLi → XSS → ссылки → чёрный список слов → фильтр по стране → AbuseIPDB → вердикт модели.
  • Требования: WordPress 6.0+, PHP 8.3+, Contact Form 7 5.7+; лицензия GPL-2.0-or-later; текстовый домен contact-form-7-spam-checker; версия в коде 4.1.1, схема базы 400.
  • Модель: 11 провайдеров через два протокола (OpenAI-совместимый и Anthropic Messages), строгие вердикты SPAM/CLEAN, отдельные ключи, переопределение base URL, политика fail-open или fail-closed, встроенный тестер.
  • Проверено 11.11.2026: архив 1 802 159 байт, SHA-256 adf6a62b…3408f; дерево 2,6 МБ; 60 PHP-файлов, 7 751 строка; php -l без ошибок по всем 60 файлам; крупнейшие модули — RestController 23 494 Б и Settings 20 259 Б.
  • Живой сайт: 24 плагина, Contact Form 7 не установлен, сам плагин не установлен — поведение в работе не проверялось.
  • 4.1.1 — патч: B1 (проверка моделью была мёртвым кодом при схеме v2, чтения переведены на llm.*), B2 (обновление 4.0 → 4.1 стирало ключ и флаг включения; миграция идёт до снимка настроек), плюс правки M1–M12, L1–L10, CI на трёх версиях PHP и переводы 396 строк на 100 % для ru/zh/de.
  • Правила дизайна: при внутренней ошибке пропускать отправку, внешние проверки — последними, у каждого вердикта есть доказательство в реестре.
  • Ссылки: https://github.com/paulmann/Contact-Form-7-LLM-Spam-Checker, https://github.com/paulmann/Contact-Form-7-LLM-Spam-Checker/releases/tag/v4.1.1

Промт для агента (установка и настройка)

Готовый промт: скопируйте блок целиком. Источник шагов — README.md и readme.txt в архиве релиза (файла AGENTS.md в дереве нет), сверено с прогоном синтаксиса и осмотром живого сайта. Файла AGENTS.md у этого проекта я не нашёл, поэтому опора — на документацию в архиве.

Задача: поставить CF7 Spam Checker Pro 4.1.1 на сайт с Contact Form 7 и настроить защиту формы без капчи.

Материалы:
- репозиторий: https://github.com/paulmann/Contact-Form-7-LLM-Spam-Checker
- релиз: https://github.com/paulmann/Contact-Form-7-LLM-Spam-Checker/releases/tag/v4.1.1
- README в архиве релиза

Шаг 1. Проверить требования: WordPress 6.0+, PHP 8.3+, Contact Form 7 5.7+.
Шаг 2. Скачать архив релиза и сверить SHA-256.
Шаг 3. Распаковать в каталог плагинов, активировать в админке.
Шаг 4. Включить локальные слои: honeypot, тайминг, частотный лимит, чёрный список слов, ограничение ссылок.
Шаг 5. Отправить тестовую заявку и найти её вердикт в реестре.
Шаг 6. Настроить AbuseIPDB: ключ, три порога, TTL кеша ответов.
Шаг 7. Подключить провайдера модели, проверить соединение встроенным тестером, задать политику при ошибке.
Шаг 8. Выставить срок хранения записей реестра и частоту уведомлений.
Шаг 9. Проверить эскалацию: временный бан после N нарушений, постоянный после повторов.

Запрещено:
- считать слой включённым, если не отправлена тестовая заявка с записью в реестре (так проверка моделью была мертва в 4.0);
- ставить fail-closed на форму обратной связи без понимания последствий: при сбое провайдера заявки не пройдут;
- включать автобан по вердикту модели без проверки на ложные срабатывания;
- хранить записи реестра дольше, чем нужно: это персональные данные посетителей;
- ставить плагин на сервер с PHP ниже 8.3: он не запустится;
- выдавать отсутствие ошибок линта за проверку работы.

Что считать успехом: тестовая заявка сначала попадает в реестр как спам по локальному правилу, затем — как чистая при отключённом правиле; AbuseIPDB отвечает и показывает квоту; модель возвращает SPAM или CLEAN; уведомления приходят.