Кто и как борется со спамом?

Нужен совет.
Кто и как борется со спамом на email в modx при использовании ajaxform и formit?
Или даже без привязки к modx а просто, какие действенные способы борьбы вы знаете?

У меня много сайтов на modx и везде установлена recaptcha 3 версии и плюс проверка того, что скрытый input в форме остается пустым. Но спам все равно идет и не мало. За день с каждого сайта может приходить до 50 спам-писем. Заметил, что спам на сайтах становится сильнее, если наши СЕО специалисты начинаю продвигать проект, потом спадает, затем снова усиливается, и только на совсем забытых и заброшенных проектах он отсутствует совсем (как впрочем и обращения от людей).
Есть около 10 ка сайтов на битриксе — там тоже самое, никакие встроенные в битрикс каптчи или подключение гугл каптч — не помогают от слова совсем.

На сайтах которые я делаю с нуля на микрофремворке slim я использую следующее решение — я верстаю форму не используя тег form. Ведь все равно обработчики я пишу свои на javascript и мне не нужно чтобы форма была классической. И это помогает на самом деле, такие формы остаются незамеченные спам ботами.
Но такой подход или нельзя или довольно проблематично использоваться с ajaxform и formit, ведь они нацелены на событие submit, которое возникает при отправке формы.

Поэтому и интересно, что применяют коллеги и как воюют со спамом?
Александр Мельник
27 декабря 2021, 15:52
modx.pro
5
1 752
0

Комментарии: 23

Николай Савин
27 декабря 2021, 18:28
+1
Я, например проверяю IP. Обратил внимание, что большинство запросов со спамом лезут из Европы. Потому чаще всего достаточно проверить страну отправителя. И если это не РФ (в моем случае Казахстан был) — то отклонять запрос.
Очень простенький хук на самом деле — и сильно спасает.
Не везде это конечно нужно, но в региональных магазинчиках сойдет
Вот пример кода для хука FormIT
$response = file_get_contents('https://ipwhois.app/json/?lang=ru&ip='.$_SERVER['REMOTE_ADDR']);
$response = json_decode($response, 1);
if(is_array($response)) {
    if($response['country_code'] === 'KZ') {
        return true;
    };
} 

return false;
    Александр Мельник
    27 декабря 2021, 18:43
    0
    спасибо. Это несколько неожиданно, но для сайтов которые заточены только под одну или несколько стран — хорошее решение.
      Николай Савин
      27 декабря 2021, 18:55
      0
      Мне кажется таких большинство. В особенности E-commerce
        Александр Мельник
        27 декабря 2021, 19:25
        0
        И не сталкиваетесь с тем, что сервисы которые предлагают бесплатное определение страны по IP частенько лагают, часто недоступны?
        У меня как то на одном проекте была задача — скрыть сайт от жителей Кореи, но оставить доступным всему миру. Тоже для начала выбрал какой-то бесплатный сервис, но он работал так не стабильно, часто отдавал 500 ошибки, что в итоге купили дорогой пакет.
          Александр Мельник
          27 декабря 2021, 19:29
          0
          Да наверное таких большинство. Признаюсь, идея отсеивать спам просто по принадлежности к стране мне в голову не приходила. Я делал хуки которые не позволяли отправить с одного IP чаще чем раз в секунду, но не особо спасало.
      Alexey
      27 декабря 2021, 21:37
      0
      Привет! Ещё вариант: обязательное скрытое поле, которое аппендом добавляется в форму при помощи js по событию ховера на кнопку сабмита.

      На больших магазинах не тестил, но на средних работает хорошо. Во всяком случае, до установки этой ловушки спам падал по 20-50 писем в сутки, а после — как отрезало.

      Есть минус у этого способа — не отправить форму через ctrl+enter.
        Александр Мельник
        28 декабря 2021, 08:28
        0
        спасибо. Я правильно понял — при наведении на кнопку отправить добавляем input в форму с уже заранее прописанным value? А затем в валидаторах formit проверяем что этот input есть и что он не пустой?
        Интересная идея.
          Alexey
          28 декабря 2021, 09:21
          0
          Александр, да — всё верно!
          Shedko Denis
          28 декабря 2021, 19:24
          0
          Способ хороший, но только от начинающих «конкурентов».

          Хватает утилит, которые обойдут эту проверку, т.к. содержат скрытое окно хрома и там «елозят» мышкой. Но от простых атак — да пройдет. Даже капчу можно за копейки в автоматическом режиме разбирать.

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

          С reCAPTCHA не имел дело, может это решение для небольших проектов лучшее.
          Anton
          13 января 2022, 20:48
          1
          +6
          Всем привет!

          Я борюсь таким образом:
          1. Проверяю в сниппете для FormIt с помощи регулярки на наличие ссылки типа site.com И email типа name@mail.com в поле текстового сообщения + в каждом поле такую проверку делаю (Имя, Телефон, Название фирмы, все поля чекаю). Если обнаружена ссылка, то возвращаю false и сообщение, что «Ссылки или электронные адреса в данном поле не разрешены. Вы можете приложить Word, Excel, PDF или текстовый файл с подробным описанием, ссылками и email.».
          2. Использую сниппет csrfhelper:
          <input type="hidden" name="csrf_token" value="[[!csrfhelper? &key=`contact-us`]]">
          А в вызов FormIt добавляю хук csrfhelper_formit.
          3. Разумеется, добавляю простейшую проверку на пустоту скрытое поле URL (можно назвать поле любым человекоподобным словом)
          <input class="form-control visually-hidden" type="text" name="url" value="">
          4. Добавляю таймер на страницу, который не разрешает отправлять форму, если ты менее 15 секунд на странице (обычно спам-боты отправляют спам моментально после загрузки страницы, менее чем за 1-5 секунд) и показываю пользователю сообщение об ошибке «Слишком быстро нажата кнопка Отправить. Подождите, пожалуйста, 15 секунд и отправьте еще раз.»
          В форме Fenom-тэг с текущим временем в формате UNIX. Сравниваем его в антиспам-сниппете.
          <input class="form-control visually-hidden" type="text" name="formtime" value="{time()}">
          5. На всякий случай вырезаю все html-тэги из всех полей :stripTags
          6. В доработке хук, который чекает прилагаемый файл через форму: только pdf, word, excel, txt, zip, png, jpg; не больше 25 мегабайт (вроде как стандартное ограничение всеми почтовиками). Если проверка не пройдена, то показываем вежливое сообщение, что мы принимаем только такие файлы и не больше 25 мб.
          7. Не забываем про проверку на обязательность заполнения полей со стороны клиента с помощью тэга required. А также проставляем все необходимы типы данных в инпутах: type=«email», type=«number» или же type=«text» во всех полях!

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

          {$_modx->runSnippet('!FormIt', [
          
          	'hooks' => 'antiSpam,spam,csrfhelper_formit,email',
          
          	'spamCheckIp' => '1',
          	'csrfKey' => 'contact-us',
          
          	'validate' => 'name:stripTags:required,email:stripTags:required,message:stripTags:required,url:blank',
          
          	'successMessage' => '<div class="alert alert-success mt-3" role="alert"><b>Спасибо!</b> Ваше сообщение было отправлено.</div>'
          
          ])}
          Сам сниппет antiSpam:
          <?php
          $name = $hook->getValue('name');
          $phone = $hook->getValue('phone');
          $email = $hook->getValue('email');
          $message = $hook->getValue('message');
          $contact_attachment = $hook->getValue('contact_attachment');
          
          $regExpGSM = '/(\d{3})(?:(?:-*|\s*|\.*|\)*|\)\s*))(\d{3})(?:(?:-*|\s*|\.*|\)*))(\d{3})/';
          $regExpURL = '/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b[-a-zA-Z0-9@:%_\+.~#?&=]*/i';
          $regExpEmail = '/(?<=\b)\w([\w\.\-_0-9])*(@| at )[\w0-9][\w\-_0-9]*((\.| DOT )[\w\-_0-9]+)+(?=\b)/';
          $regExpExt = '/^([A-Za-z0-9-_.])+\.(png|jpe?g|gif|bmp)$/';
          
          /*Check regExp email*/
          if (preg_match($regExpEmail, $name)) {
              $hook->addError('emailInName', 'Email-адреса не разрешены в поле Имя. Вы можете приложить Word, Excel, PDF или текстовый файл с подробным описанием, ссылками и электронной почтой.');
              return false;
          } elseif (preg_match($regExpEmail, $message)) {
              $hook->addError('emailInMessage', 'Email-адреса не разрешены в поле Сообщения. Вы можете приложить Word, Excel, PDF или текстовый файл с подробным описанием, ссылками и электронной почтой.');
              return false;
          
              /*Check regExp URL's*/
          } elseif (preg_match($regExpURL, $name)) {
              $hook->addError('linkInName', 'Ссылки на сайты не разрешены в поле Имя. Вы можете приложить Word, Excel, PDF или текстовый файл с подробным описанием, ссылками и электронной почтой.');
              return false;
          } elseif (preg_match($regExpURL, $message)) {
              $hook->addError('linkInMessage', 'Ссылки на сайты не разрешены в поле Сообщения. Вы можете приложить Word, Excel, PDF или текстовый файл с подробным описанием, ссылками и электронной почтой.');
              return false;
          	
          /*И так далее по всем полям чекаю регулярками выше*/
          
          /*Проверяем, что не слишком быстро нажимается кнопка "Отправить"*/
          } elseif ($_POST['formtime'] > time() - 15) {
              $hook->addError('fastSending', 'Слишком быстро нажата кнопка Отправить. Подождите, пожалуйста, 15 секунд и отправьте еще раз.');
              return false;
          
          } else {
              return true;
          }
          В самой форме плейсхолдеры для вывода человекопонятных ошибок:
          [[!+fi.error.csrf_token:notempty=`
          <div class="alert alert-warning mt-3 mb-2">[[!+fi.error.csrf_token]]</div>
          `]]
          [[!+fi.error.fastSending:notempty=`
          <div class="alert alert-warning mt-3 mb-2">[[!+fi.error.fastSending]]</div>
          `]]
          
          [[+fi.statusMessage]]
          [[+fi.successMessage]]
          
          <input type="text" class="form-control"
                 placeholder="Ваше имя *"
                 name="name"
                 value="[[!+fi.name]]"
                 required>
          <span class="error_name">[[+fi.error.name]]</span>
          До этого у меня была всего-лишь одна проверка regExp на наличие ссылки и email в поле Сообщения (message). Спама почти не было, но стал приходить спам типа Buy our viagra on usa-pharma.shop, пропускались такие ссылки. Более длинная регулярка уже иногда блочила любой текст, если юзер пишет сообщение и после точки сразу пишет слово нового предложения.

          Добавил проверку на 15 секундное ожидание (человеку просто не реально раньше 15й секунды заполнить все поля и отправить форму). Можно поставить 5 секунд.

          После этого стали приходить сообщение только от человеков, никакого спама.

          Не отловленные ошибки надо бы логгировать (у меня был этот кусок кода для логгирования не отправленных форм через FormIt, но не могу найти, он в старых хуках был).

          Ну и можно по IP блочить вдобавок, как выше уже предложено.

          Я не очень силен в PHP, как смог так и написал, поэтому большая просьба помочь хорошо доработать данный сниппет/хук и поделиться им здесь.
            Александр Мельник
            14 января 2022, 09:19
            +1
            спасибо за такой развернутый ответ.
              Николай Савин
              14 января 2022, 09:48
              +3
              Александр, а чего бы вам, раз уж зашел разговор не написать развернутый материал на тему «101 способ защиты от спама в MODX». Собрать все что упоминалось, сделать какой-то обзор плюсов и минусов. Будет огромная польза для сообщества и вам для кармы
                Александр Мельник
                25 января 2022, 18:03
                0
                Спасибо Николай за доверие. Я подумаю над этим, хотя просто копипастить чужие идеи не хочется, хочется рассказать о своем опыте, а он пока негативный. Особо победить спам там и не вышло.
                  Николай Савин
                  25 января 2022, 18:06
                  0
                  Лучше собрать чужой опыт в одном удобном руководстве, чем не размещать свое вообще нигде.
                  Мы все учимся на чужом. Я до сих пор подсматриваю какие то технические решения в чужом коде. И использую удачные решения. Плюсь правда все чаще с каждым годом, но это уже другая история.
            Futuris
            25 января 2022, 17:05
            0
            А если не секрет, из каких соображений вы используете slim? Вы, как я понял, развиваете и поддерживаете множество сайтов на разных платформах. И в каких случаях вы принимаете решение вместо традиционных CMS с админ. панелью использовать микрофреймворк?
              Александр Мельник
              25 января 2022, 18:18
              0
              Вы правы. Специфика работы той фирмы в которой я «программист» — это не разработка сайтов. Основной упор делается на СЕО продвижение, поэтому к нам приходят (ну или мы ищем) уже готовые сайты, на которые все махнули рукой разработчики, а заказчики недовольны прибылью от сайта. В данном контексте программист получается лишь придатком, цель которого исполнять бесчисленные и иногда бессмысленные идеи наших сео специалистов. Сайты приходят разные, сделанные на чем угодно, поэтому и работать приходится со всем подряд.
              Но все же в 30 процентах случаев мы делаем заказчику новый сайт. И тогда я уже стараюсь хоть примерно (как правило заказчик сам понятия не имеет что ему нужно да и сео специалисты тоже) пытаюсь провести анализ и выбрать инструмент. Если это что то очень простое и на всю разработку дается 4-5 дней, то делаю на modx или opencart. Если позволяет время и я вижу, что проект по моим меркам средний или выше среднего по сложности — выбираю slim.
              Наверное есть и вторая причина, почему выбираю не modx. Я не умею делать на нем красивые админки. Когда в админке работают наши контент менеджеры, то они привыкли к админке modx. Но если в админке будет работать заказчик — они все поголовно жалуются, что сложно, ничего не понятно, какие-то ресурсы…
              А slim позволяет разработать свою админку, лаконичную и понятную.
              Почему именно slim — наверное люблю минимализм. Смотрел в сторону laravel и понял что он мне не приятен именно тем, что в нем многое уже реализовано. Разговаривал с одним своим коллегой, просил его рассказать что такое storage в laravel, потому что сам не очень понял. Он сказал — а зачем ты пытаешься понять, вот же в документации написано — пишешь вот это, вызываешь такой то метод и все. Я так не люблю, мне такой подход не нравится.
              Как раз в данную минуту разрабатываю личный кабинет для клиентов компании воздушного такси.
                Николай Савин
                25 января 2022, 19:16
                0
                А чем принципиально отличается разработка админки под slim от разработки простой админки под MODX?
                  Александр Мельник
                  25 января 2022, 19:58
                  +1
                  Наверное только тем, что для MODX я этого делать не умею)
                  Ну и в моем мировозрении это несколько странно. Систему нужно либо принимать как она есть или не принимать совсем.
                  Хотя несколько раз я делал нечто подобное, если клиенты уж совсем психовали — делал отдельные страницы для управления некоторыми данными, которые не были связаны с админкой и «закрыты» теми или иными способами. Но это скорее исключение из правил.
                  Плюс мне «удобно думать» в концепции MVC, а в MODX она очень искажена на мой взгляд.
                  Как то вот комфортно мне в той микросреде, которую я вокруг slim себе создаю — slim, composer, orm doctrine, twig, php-di, классический mvc, поддержка стандартов psr-7, middleware и psr-15, стараюсь использовать чистый js и parcel (кстати отличная альтернатива излишне замороченному webpack)
                  Futuris
                  26 января 2022, 09:07
                  0
                  slim, composer, orm doctrine, twig, php-di
                  Ну т. е. это комфортная для вас «творческая» среда, в которой вы, видимо, можете сделать что угодно. А не то, чтобы выбор slim зависел от каких-то специфических требований заказчика.
              Эдуард
              04 февраля 2022, 11:47
              0
              Я добавляю вот этим js кодом в каждую форму скрытое поле nobot сразу после загрузки любой страницы
              $('form').prepend('<input type="hidden" name="nobot" value="1">');
              И в formit его проверяю как обязательное, автоспама вроде нету и только ручной попадается иногда
                Александр Мельник
                04 февраля 2022, 12:51
                0
                Спасибо. Но я не могу понять, как это может помочь?
                Если данный инпут вставляется на событие загрузки страницы, то она произойдет и у «бота».
                В 2022 году спам боты это очень совершенные программы, умеющие имитировать поведение пользователя на высоком уровне.
                Но раз помогает, то наверное я в чем то не прав.
                  Эдуард
                  04 февраля 2022, 13:10
                  +1
                  Да от программ с безголовыми браузерами и эмуляторов браузеров этот метод не спасет конечно.
                  Но такой метод рассылки дороже обходиться спамерам, я так понял им пользуются уже те, у кого есть время и деньги и кто нацелен уже конкретно на какой-то сайт или сеть сайтов. Проспамить какую-то слитую где-то общую базу в миллион сайтов этим методом очень долго.
                  А дешевые методы спама не используют эмуляцию браузера, но могут обработать кучу сайтов.
                Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
                23