100% защита от автоспама в комментариях

Начну с того, что покажу скриншот того, что творилось на одном из моих блогов ещё в конце прошлого года.

пример автоспама админка wordpress

Трудно поверить, верно?

Причем, папку спам я постоянно очищаю, это комментарии за один раз — за промежуток времени, в течение которого я не заходил в админку (не больше месяца).

Часть комментариев была на английском, остальные либо рекламировали строительные материалы, либо паленую электронику, либо курсы, которые научат, как разбогатеть за неделю.

Полный бред.

Так как все эти комменты оставляют боты, то их легко можно обмануть.
Бот заточен под WordPress? — значит надо сделать форму комментариев, не похожую на стандартную вордпрессовскую.

<form method="POST" name="commentform">
	<input type="text" name="author" id="author" />
	<input type="text" name="email" id="email" />
	<textarea name="comment" id="comment"></textarea>
</form>

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

	<textarea name="comment" id="comment"></textarea><!-- фейк -->
	<textarea name="true_comment"></textarea><!-- настоящее -->

Теперь надо, чтобы WordPress понимал, какое поле настоящее, а какое нет и в случае чего давал пенделя кому следует. Этот код — в functions.php

function stop_spam($commentdata) {
	$fake = trim($_POST['comment']);
	if(!empty($fake)) wp_die('Ошибка!');
		$comment_content = trim($_POST['true_comment']);
	$_POST['comment'] = $comment_content;	
	return $commentdata;
}
 
add_filter('pre_comment_on_post', 'stop_spam');

Ах да, ведь теперь же у нас два поля для ввода комментария 🙂
Заюзаем CSS.

#comment{
	position:absolute;
	left:-9000px;
}

Функция comment_form()

Нет, я не буду сейчас описывать эту функцию (описанию функции comment_form() посвящен отдельный пост), скажу лишь что, начиная с версии WordPress 3.0, она может отвечать за вставку формы комментария.

Что делать, если она используется на вашем блоге? Нужно в functions.php добавить ещё кое-что (то, что мы добавляли раньше, удалять не нужно).

function edit_comment_form_fields($default) {
	$commenter = wp_get_current_commenter();
	$default['comment_notes_after'] .= 
	'<p class="comment-form-true_comment">
	<label for="true_comment">Ваш комментарий:</label>
	<textarea id="true_comment" name="true_comment" rows="8" cols="45" aria-required="true"></textarea>
	</p>';
	return $default;
}
 
add_filter('comment_form_defaults', 'edit_comment_form_fields');

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

Почему перестала работать защита от спама с подменой полей в WordPress 4.4 и как это исправить?

В WP 4.4 изменился код файла wp-comments-post.php, находящегося в корне вашего сайта, таким образом, что наш хук pre_comment_on_post запускается слишком поздно и уже не успевает выполнять свою функцию. Альтернативы в виде хуков я не нашёл, поэтому представляю вам другое, также весьма простое решение.

  1. Если у вас ещё используется хук из предыдущего шага, удалите его.
  2. В корне сайта создайте файл с произвольным названием, например antispam.php и поместите туда следующий код:
    <?php
    $fake = trim($_POST['comment']);
    if(!empty($fake))
    	exit;
    $_POST['comment'] = trim($_POST['true_comment']);
     
    require( dirname(__FILE__) . '/wp-comments-post.php' );
  3. Замените атрибут формы action на ссылку на этот файл (antispam.php). Если вы используете comment_form() для вывода формы, то замену проще всего сделать через JavaScript.

Миша

В последние годы я долго не знал, что мне делать с сайтом misha.blog, ведь он практически не приносит никакого профита, но недавно я осознал, что моя миссия – способствовать распространению WordPress. Ведь WordPress – это лучший движок для разработки сайтов – как для тех, кто готов использовать заложенную структуру этой CMS, так и для тех, кто предпочитает headless решения.

Сам же я впервые познакомился с WordPress в 2009 году. Организатор WordCamp. Преподаватель в школах Epic Skills и LoftSchool.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля на WordPress / WooCommerce — пишите. Я и моя команда сделаем вам всё на лучшем уровне.

Комментарии — 66

  • sikor 7 марта 2012 #

    Все получилось. Как я понял, если использовать форму комментариев из этого поста, то можно не использовать код

    function stop_spam($commentdata) {
        $fake = trim($_POST['comment']);
        if(!empty($fake)) wp_die('Ошибка!');
            $comment_content = trim($_POST['true_comment']);
        $_POST['comment'] = $comment_content;
        return $commentdata;
    }
     
    add_filter('pre_comment_on_post', 'stop_spam');

    - форма комментариев остается пустой и спам не отправляется.
    Удалил плагин Antispam Bee. Спасибо.

    • Миша 7 марта 2012 #

      пожалуйста))

  • sikor 7 марта 2012 #

    Побольше бы таких постов о замене плагинов на код.

    • Миша 8 марта 2012 #

      можешь высылать предложения мне по email)

    • Владимир Жданов 25 апреля 2012 #

      Михаил, ты не будешь против если я оставлю ссылку на пост где я описал большое колличество замен плагинов на код?

      • Миша 25 апреля 2012 #

        тогда уж можно просто обменяться контекстными ссылками)

  • Otshelnik-fm 11 марта 2013 #

    Странно что я не находил ваш блог в рунете. Случайно попал на него сегодня и остаюсь!

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

    Спасибо за сайт. Буду следить за вами )))

    • Миша 12 марта 2013 #

      Спасибо))
      мой блок яндекс не очень любит) наверное из-за того, что большинство статей довольно короткие

      • Otshelnik-fm 12 марта 2013 #

        Проиндексировано яндексом чуть меньше чем гуглом. А вот обратных ссылок дает яндекс на вас больше чем гугл. Так что кто еще кого не любит)).

        А вас нашел через гугл т.к. в техническом плане он лучше ищет.

        • Миша 12 марта 2013 #

          ну я чисто по google analytics смотрю, с яндекса посещений ровно в два раза меньше, чем с гугла)

  • Александр 16 июля 2013 #

    Изящное решение. WP не перестает удивлять.

  • Волшебник 15 июня 2014 #

    Интересное решение. У меня несколько вопросов по этому.

    1. Допустим мне не нужно в форме комментариев поле с адресом сайта. Как его можно тоже задействовать в дополнение к этому решению? Например скрыть это поле средствами CSS и если оно заполнено, то удалять такие комменты сразу. Или этого не требуется и основной способ с одним полем срабатывает всегда 100%?

    2. При данном способе всё отсеянное улетает в папку "спам" или удаляется сразу? Хотелось бы чтобы удалялось сразу.

    3. Можете посоветовать какой-нибудь плагин, делающий то же самое? Т.к. при наличии множества тем оформления, вносить изменения в каждую немного проблематично.

    • Миша 16 июня 2014 #

      1. Если поле сайта не нужно, его лучше удалить (через PHP, но никак не через CSS). Да, 100% против автоспама.

      2. Не добавляется вообще, как написал @Otshelnik-fm ниже, WordPress прервет обработку и коммент не добавится в базу - а значит не будут потрачены ресурсы сервера.

      3. Плагинов подобного рода не встречал. Ну тут в принципе нетрудно написать его самому.

  • Otshelnik-fm 15 июня 2014 #

    Волшебник привет.
    Этот способ работает 100% и не обязательно удалять поле сайта.
    wp_die('Ошибка!') - показывает, что спамеру будет показываться чистый лист с единственной надписью, а сам комментарий не пройдет в базу данных - т.к. вордпресс прервет обработку. В итоге нет в админке помеченных спамом записей. Там будет чисто.

    На днях вот еще один свой сайт перевел на этот метод, когда за сутки спамом написали 2000 комментариев и хостер прислал сообщение о перегрузке сервера. Заняло минут 10 все изменения. Теперь всё чисто и только люди ручками могут оставить свой комментарий.
    А за год использования на другом сайте автоботы не прошли))

  • Волшебник 16 июня 2014 #

    Если тема использует стандартный код вызова, вида comment_form(), то проблем нет. Однако некоторые темы модифицируют форму отправки коммента. Что делать, если код вызова комментариев (в comments.php) например такой:

    comment_form(array('comment_notes_after' => '', 'title_reply' => __('Leave a comment','themead')));

    • Миша 16 июня 2014 #

      Ну опять же получается, что через comment_form, а значит можно повесить хук.

  • Волшебник 17 июня 2014 #

    В общем всё настроил, отключил акисмет, посмотрим на результаты. Акисмет в принципе не пропускает спам-комментарии, но раздражает, что некоторый спам он всё равно складывает в папку "спам", а не удаляет сразу.

    А почему бы ложное поле не скрыть в display:none? Или боты просекут?

    • Миша 17 июня 2014 #

      Akismet коварный, он может так базу данных забить, что мало не покажется.

      Думаю можно и через display: none;. Относительно того, просекут или нет - вроде не просекают, у меня раньше так стояло.

  • Волшебник 19 июня 2014 #

    Отличный метод. До сих пор ни одного спама не прошло )
    Думаю, если сюда добавить рандомный код вместо одного и того же id="true_comment", чтобы всегда менялось и нельзя было привыкнуть и еще одно поле, то будет 200% защита от спама.

    Можно еще добавить проверку на заполнение скрытого поля вебсайта, которое боты обычно всегда заполняют.

    • Otshelnik-fm 19 июня 2014 #

      так вы прям id=”true_comment” и вписали? 🙂
      я указал свой уникальный. как только хоть один спамбот его разгадает - поменяю на другой неповторимый id

      Усложнять функцию не надо - у меня больше чем за год использования функции мой id стоит и не разгадали. Всё работает как часы.

  • Волшебник 19 июня 2014 #

    Ну да, true_comment и вписал) Но даже так работает) Да и не думаю, что кто-то там будет разгадывать, это нецелесообразно, т.к. боты нацелены на массовую рассылку, поэтому используется массовый алгоритм. Подбирать ключи к части сайтов, где используется другой алгоритм - уже слишком затратно.

  • Jason 28 ноября 2014 #

    У меня почему-то не работает 🙁
    Использую твои аякс-комменты, а так же оба хука из этой статьи. При заполнение фейкового(name=comment) поля даёт ошибку, а при заполнении правильного(name=true_comment) требует заполнить фейковое...

    • Миша 29 ноября 2014 #

      Где-то напутал с названиями полей просто. Просмотри ещё раз свой код.

  • Волшебник 11 февраля 2015 #

    Код отлично зарекомендовал себя. За несколько месяцев работы не прошел ни один бот.
    Попробую прикрутить его и на форумный движок для защиты от ботов.
    Разные акисметы, капчи и прочее - это просто усложнение на пустом месте.

  • Волшебник 18 февраля 2015 #

    Прикрутил к форуму импровизированный php скрипт. Боты больше не проходят.
    У меня еще такая мысль появилась - получаем IP адрес заполнившего ложное поле и добавляем его в .htaccess в список deny from, и навеки прощаемся с ботом. Ведь хоть коменты то не проходят, но эти же самые боты всё равно продолжают бомбить ежедневно сайт по много раз. Например я в логах насчитал за сутки более 50 заполнивших ложные поля, из них 95% прилетают с одного-двух ip адресов и они посещают сайт каждый день.
    Можно так же туда вносить всех, то пытается лезть в запрещенные адреса.
    Пример реализации gist.github.com/dimlife/5799050

    • Миша 18 февраля 2015 #

      Для ботов с постоянными адресами — да.

      Просто бомбить могут и вирусы с компов обычных пользователей + динамические IP-адреса никто не отменял)

  • Волшебник 18 февраля 2015 #

    Ну... можно вести учёт, например записывать лог за сутки, в конце суток, самый активный адрес с которого идёт спам, блокировать навсегда в htacess. Таким образом мы на автомате отсекаем бОльшую часть самых активных ботов, с которых валится 90% спама.

    • Миша 18 февраля 2015 #

      Ну да, если брать те IP-адреса, с которых приходит преимущественно только спам.

      Блин, тупые спамеры, неужели это приносит им хоть какой-то эффект??

      • Волшебник 18 февраля 2015 #

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

  • Роман llgr 29 апреля 2015 #

    Я обновился до wp 4.2.1. и отправка комментариев через созданное поле перестала работать.
    Если убрать доп.поле и отправлять через обычный textarea - то всё ок.
    Нужно как-то изменить код?

    • Миша 29 апреля 2015 #

      Хм, у меня вроде всё работает на wp 4.2.1.

      • Роман llgr 30 апреля 2015 #

        Моя проблема связана с валидацией формы комментирования. Когда валидация появилась?)) как раз в 4.2.1? вообще размер исходного файла /wp-includes/comment-template.php подрос с последним обновлением. Я так и не понял.
        Консоль отдаёт ошибку "An invalid form control with name='comment' is not focusable." Естественно форма с name='comment' спрятана за display:none; а отправлять я пытаюсь свою name='llgr-comment'.
        Если в лоб к

        <form>

        добавить novalidate, тогда всё отлично отправляется. Как через functions.php добавить это novalidate я не придумал. Да и правильно ли так делать?

        Моя страница, если будете смотреть http://dogshow.me/blog/kakoy-vyistavochnyiy-povodok-ringovku-kupit

        • Миша 30 апреля 2015 #

          Я вижу у проверочного поля атрибуты aria-required="true" required="required".

          • Роман llgr 30 апреля 2015 #

            Да-да, точно-точно, спасибо!

  • Эльдар 18 мая 2015 #

    После обновления wp 4.2.1 защита перестала работать , комментарии не отправляются.

    • Миша 19 мая 2015 #

      Эльдар, возможно два предыдущих комментария решат вашу проблему.

  • Максим 14 декабря 2015 #

    После обновления wp до версии 4.4 защита перестала работать , комментарии не отправляются. Как можно починить?

  • Максим 14 декабря 2015 #

    Пишет: ОШИБКА: пожалуйста, введите комментарий.

    • Миша 15 декабря 2015 #

      Можете по почте скинуть доступ к сайту?

      • Максим 15 декабря 2015 #

        Решил проблему установкой плагина Antispam Bee - он работает по такому же принципу.

    • Роман 23 декабря 2015 #

      Миша, ты не смотрел в чём проблема?
      WP 4.4 очень хочет чтобы заполняли именно такое поле:

      <textarea id="comment" name="comment"></textarea>
  • Максим 23 декабря 2015 #

    Привет после обновления вордпресс тоже не работает форма отправки комментария пишет ОШИБКА: пожалуйста, введите комментарий. Решите пожалуйста проблему мой блог seoslim.ru

    • Миша 23 декабря 2015 #

      Привет, на этой неделе постараюсь разобраться.

      • Владимир 23 декабря 2015 #

        Тоже такая же хрень но только на сайте http://vzglyad.net.ua а вот на сайте http://smart-rabota.ru все нормально работает причем на обоих сайтах плагины примерно одинаковые различие только в темах .... посмотри будь добр что может быть ? вордпресс на обоих сайтах стоит 4.4

  • Максим 23 декабря 2015 #

    Привет, пока проблему решил следующим образом, заменил в корне сайта обновленный файл wp-comments-post.php на старый, что был до обновления и проблема ушла. Но это не выход, каждый раз править файлы.

    • Владимир 23 декабря 2015 #

      Сейчас попробую ....

    • Владимир 23 декабря 2015 #

      Да проблема ушла заменой нового файла wp-comments-post.php на старый значит надо сравнить два файлика

      • Миша 25 декабря 2015 #

        В общем да, пока что это единственный вариант.

        Дело в том, что в старой версии мы могли поменять значения $_POST до того, как они обрабатывались вордпрессом.

        Теперь значения $_POST записываются в отдельную обычную неглобальную переменную до хука pre_comment_on_post. Так как переменная не глобальная, то внутри хука мы ничего не можем с ней сделать (если ошибаюсь - поправьте).

        Что это значит? Ждём новую защиту от спама, а та, которая находится в этом посту, работает только до WP 4.4. Увы.

        В качестве временного решения, можно последовать совету Владимира.

        • Владимир 25 декабря 2015 #

          так получается не вордпресс дело? у меня на одном сайте все работает и без отката а вот на двух других с одинаковыми темами пришлось откатить....

          • Миша 25 декабря 2015 #

            В WP полностью изменился wp-comments-post.php и его функции.

            • Владимир 25 декабря 2015 #

              мистика какая то .....

              • Роман 25 декабря 2015 #

                Покажи сайт на wp 4.4. где продолжает работать

                • Владимир 25 декабря 2015 #

                  smart-rabota.ru на этом ни чего не откатывал

                  • Миша 25 декабря 2015 #

                    Так у вас там и не стоит данного хука 🙂 разве нет?

                    В общем постараюсь на праздниках соорудить какую-нибудь альтернативу.

                    • Владимир 25 декабря 2015 #

                      обновлял все три сайта на автомате может что не обновилось ... а так ждем от вас альтернативу и С Наступающим всех !!!

                    • Роман 25 декабря 2015 #

                      В общем с наступающим, парни)

                    • Миша 26 декабря 2015 #

                      C Наступающим 🙂

  • VRS 28 декабря 2015 #

    Спасибо, Миша.
    Твой блог как всегда помогает держать руку на пульсе, а то я бы еще неизвестно сколько времени бродила в поисках ответа, почему не работает pre_comment_on_post.
    С наступающим Новым годом!
    Поменьше бы нам таких неприятных сюрпризов в нем).

    • Миша 28 декабря 2015 #

      C Наступающим 🙂 Да, хотелось бы поменьше))

    • Миша 29 декабря 2015 #

      Обновил пост для версии 4.4. Большая просьба протестировать код, я не успеваю 🙂

      • Роман 3 февраля 2016 #

        Миша, привет!
        Научи как можно заменить атрибут формы

        action

        на ссылку на файл antispam.php не через JavaScript?

        • Роман 3 февраля 2016 #

          Ответ для functions.php:

          add_action( 'comment_form_before', 'my_comment_form_before' );
          function my_comment_form_before() {
          	ob_start();
          }
          add_action( 'comment_form_after', 'my_comment_form_after' );
          function my_comment_form_after() {
          	$html = ob_get_clean();
          	$html = preg_replace('/wp-comments-post.php/','antispam.php',$html);
          	echo $html;
          }

          Ну вроде способ защиты по-прежнему рабочий, да?

  • Анастасия 6 февраля 2016 #

    Миша, добрый день.
    А если с хука pre_comment_on_post перевесить на пораньше, например, init, то заработает и старый вариант

    • Миша 8 февраля 2016 #

      Добрый день!
      Буду благодарен за пример. Не помню почему, но вроде у меня что-то не получалось с pre_comment_on_post.

      • Анастасия 8 февраля 2016 #

        Добрый день.

        Вот вы пишите: "наш хук

        pre_comment_on_post

        запускается слишком поздно и уже не успевает выполнять свою функцию"

        Вместо

        pre_comment_on_post

        берем

        init

        , например, который запускается значительно раньше.

        У меня нормально работает вот такой код:

        add_filter( 'comment_form_defaults', 'antispam_comment_form_textarea' );
        function antispam_comment_form_textarea( $defaults ) {
        	 $defaults['comment_field'] = '<p class="comment-form-comment"><label for="comment">Ваш комментарий</label><textarea id="comment" style="display: none;" name="comment"></textarea><textarea id="real-comment" name="real-comment" cols="45" rows="8" aria-describedby="form-allowed-tags" aria-required="true"></textarea></p>';
        	$defaults['comment_notes_after'] = '';
          	$defaults['title_reply'] = __( 'Поделитесь своими мыслями' );
        	return $defaults;
        }
         
        // Защита от спама в комментариях
        add_filter('init', 'verify_spam');
        function verify_spam($commentdata) {
              $spam_test_field = trim($_POST['comment']);
          if(!empty($spam_test_field)) wp_die('Спаму нет!');
              $comment_content = trim($_POST['real-comment']);
              $_POST['comment'] = $comment_content;
          return $commentdata;
        }
        • Миша 8 февраля 2016 #

          Отлично, спасибо за код 🙂

Оставить комментарий

Если вы хотите добавить код, не забудьте обернуть его в <pre lang="php"></pre>, если же код – меньше одной строчки, то можно и в <code></code>.