Спам по формам без капчи (eForm)

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



Затем бот сбегает с сайта, а в почту приходит какое-то очередное «оно».

Варианты решения проблемы без внедрения капчи

Рассматриваю только отмену отправки, а не пост-обработку. Сразу оговорюсь, что я не программист, и такие решения, может быть и весьма неидеальные, но зато лезть глубоко в кишки не нужно.

0. Для всех случаев такого рода лично я отключил вывод [+validationmessage+] и занулил requiredClass и invalidClass для усложнения изучения ответа при неправильной отправке. Пре-валидацию в простой форме можно сделать и на JS и аттрибута required достаточно. ИМХО.

1. По совету Dmi3yy создание пустого поля, обязательного к незаполнению. Например, такого:
<input value="" name="phone" id="phone" class="special" type="text" eform="Спец:date:0" placeholder="Phone*">
Необходимо спрятать это поле с глаз долой через CSS и дать ему часто используемое имя. В моем случае, после того, как стал сыпаться спам у одного из клиентов — не прокатило. Только позже я понял, почему. Скорее всего, простой бот считает количество элементов в DOM, и пишет в поля по счету, не ориентируясь на ID и name. Поле надо вставить так, чтобы сломать текущий порядок элементов внутри формы. Неплохо было бы делать это в случайном порядке, но eForm не любит, чтобы кто-то копался в шаблоне формы без его ведома, а на JS этого не сделать, потому что бот не скачивает JS.

2. Хардкор. Так я сделал на некоторых статичных сайтах, где форма отправляется не очень сложным скриптом на PHP. Сделать поле имя только на русском языке.
через eForm это делается так
<input type="text" class="inptext" name="name" id="name" eform="Ваше имя::1::#REGEX /^[А-Яа-яЁё ]+$/u" placeholder="Ваше имя*">
По понятным причинам — «трудно недооценивать всю предсказуемость тупизны» не самое идеальное решение. Но внезапно оказалось, что действенное.

3. Сделать форму подгружаемой в блок на странице скриптом и отправку через ajax. Вариантов реализации можно придумать несколько, у кого на что фантазии хватит. Или в форме заменить action на несуществующий, а POST на GET и по факту показывать вместо формы только ее верстку, которую «чинить» яваскриптом при отправке, а сам правильный вызов eForm сделать на странице, куда форма отправляется. Не спасет, если эту страницу с «чистым» вызовом eForm найдет бот. Но и тут тоже возможны варианты. Например, не отображать форму, если страницу не передано какого-нибудь интересного GET-параметра, содержащего неведомую строку. Забить значение этого параметр можно куда-нибудь в настройки через cfgTV или globalPlaceholders и периодически его менять.

4. Похоже на пункт 1, но к полю пишется атрибут required и мусор в value. Так как поле по условию проверки обязано быть пустым — форма не отправится. При отправке по событию submit через JS снимается атрибут required и чистится значение. Без скриптов отправка невозможна. Аналогично можно сделать проверку на соответствие строго заданному значению и проставлять это значение при загрузке страницы, но мне кажется, это менее интересно.

9 комментариев

avatar
Я способом №3 давно пользуюсь и никакого спама. А на странице с чистым вызовом сниппета:

if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest')){
        $modx->sendErrorPage();
}

Если паранойя, то можно еще каких-нибудь заголовков добавить при отправке запроса и проверять их.
avatar
Не все формы постятся по дефолту через ajax, но ваше решение интересно и лаконично.

У меня такая смесь из разных видов отправки, что не везде зайдет, где-то целиком аякс, когда форма грузится в пустое модальное окно и в него же отправляется, где-то из скрытого слоя показывается в окно и постится не в аякс, а просто с переходом на страницу спасибо, где-то просто на странице показывается и на нее же постится, есть даже вариант, когда форма в странице, а постится в пустое модальное окно :)
Комментарий отредактирован 2017-04-22 16:34:07 пользователем alexbeep
avatar
Попробовал таким образом. Написал снипет

<?php
if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest')){
$modx->sendErrorPage();
}else{
return($modx->getChunk('eFormSender'));
}

С отключенным яваскриптом возвращает 404-ю страницу (правда, с правильным урл, тем что в action) и всё равно отправляет форму. Что я не так сделал?

UPD поставил другой редирект — $modx->sendRedirect("/404"); так работает и перекидывает правильно
Комментарий отредактирован 2017-04-25 23:23:06 пользователем alexbeep
avatar
$modx->sendErrorPage() и должен возвращать 404-ю страницу не меняя url. А вот форма при этом отправляться не должна никак, раз на 404 странице нет обработчика.
avatar
Вот я протупил! Я у страницы 404 сделал такой же шаблон как у всех текстовых, а форма там есть с такими же полями. Все работает как задумано!
avatar
Подох этот код на 1.4, писал в телеграм по этому поводу
avatar
Как вариант способа №2, можно ссылки в тексте запретить:
<textarea name="txt" eform="Текст::0::#REGEX /^(?:(?!\w+\.\w+).)*$/"></textarea>
avatar
Стояли вышеприведенные способы защиты, но под один сайт написали бота, который обходил эти защиты.
Добавил один способ — заключается в проверке наличия куки, которую ставит Яндекс Метрика или Гугл Аналитика
avatar
adblock режет метрику по умолчанию. Еще в браузере может быть встроенная защита от отслеживания, она тоже режет, напимер, на новом фаерфоксе из коробки включено. Таких юзеров много
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.