Одному моему товарищу знатно наливали спамных комментариев в WordPress, а ставить какие то капчи не хотелось, можно было бы конечно поискать поставить плагин без капчи … но я честно говоря не особо люблю плагины, т.к. нет ничего лучше собственно написаного или отревьювеного кода (если конечно понимать что делать), кроме того я уже делал нечто подобное защищая от спама Contact Form 7 без капчи, и подумав что делов тут — «херак, херак и в продакшн» сел за дело.
Однако проблема оказалась сложнее чем я думал, однако в результате все получилось — поехали.
Финальный вариант защиты Worpress от спама без капчи и плагинов
- Прописываем в код шаблона временную метку, когда страница была запрошена
- При отправке формы — обработчик проверяет, сколько времени пользователь провел на странице до отправки комментария, если менее Х секунд. то это спамер (в моем случае пауза стоит 30 секунд, согласитесь 0 если пользователь что-то читал на странице- то он врядли за минуту всё прочитал, да и еще коммент успел оформить, на
кол503 ошибку его), если поле пришло пустое — то это тоже спамер.
Вот что получилось в итоге
add_filter( 'comment_form_default_fields', 'add_antispam_field_to_comment_form' ); add_filter( 'comment_form_fields', 'add_antispam_field_to_comment_form' ); function add_antispam_field_to_comment_form($fields) { //Эта функция добавляем поле с именем csrf в форму $fields['csrf'] = ' <input type="text" name="csrf" required style="display:none"> //добавляем само поле <script>document.getElementsByName("csrf")[0].value="'.time().'"</script> //заполняем его текущей меткой времени через Javascript '; return $fields; } add_action( 'pre_comment_on_post', 'action_check_hidden_field' ); function action_check_hidden_field( $comment_post_ID ){ //Функция проверяет прошло ли Х секунд с между моментом отрисовки страницы и отправкой комментария. $human_pause = 30; //это и есть Х., т.е. в данном случае Х = 30 секунд if (!isset($_POST['csrf']) || ((time() - intval($_POST['csrf'])) < $human_pause) || !preg_match('/\d{10}/',$_POST['csrf'])) { //Если поле пришло пустое, коммент запостили раньше чем через Х секунд, или в коменте пришла какая то ерунда, а не метка времени ... wp_die('Service Unavailable','Service Unavailable', 503); // .. то покажем ошибку и коммент не запостим } } //Опционально, можно не вставлять. function remove_form_novalidate() { remove_theme_support( 'html5' ); //уберем поддержку html5 в нашей теме, чтоб снизить нагрузку на хостинг, в случае если спам-агрегат работает через свой браузер - он не даст ему отправить комментарий и он даже не дойдет до обработчика }
полученный код нужно вставить в functions.php вашей темы, Enjoy!
Код по максмуму откоменчен, так что что за что отвечает — думаю понятно. При необходимости можно заменить паузу для проверки «на человека» и название поля.
Конечно это не идеальный способ защиты комментариев WordPress от спама без капчи и обойти его несложно, однако спам проходит методом «ковровых бомбардировок» и заморачиваться с одним каким то конкретным сайтом врядли будут. Если спам в комментарии все равно идет — вам не повезло и вас заказали ))), либо неверно вставлен код
Знаете еще какие то несложные способы? Пишите в комментариях, только не ранее чем через 30секунд после прочтения поста 🙂
В форму можно втыкать поле type=hidden. Ajax’ом запрашивать значение и вставлять в поле. На сервере его в сессию.
При получении данных сравнивать 2 значения.
Работает у меня так везде. И нет временных ограничений.
Количество спама сразу же упало до нуля.
Метод хорош, только если спамбот исполняет JS, то пробьет.
Хотя можно скомбинировать и будет пушка.
Спасибо за интересное решение. Но если включено кеширование на сервере — дата тоже закешируется и все спам-комменты будут валидны?
Звучит логично, однако возможно плагины кеширования как то обрабатывают то что хуками вставляется, т.к. юзали и WP-Rocket и еще какой то плагин — все было нормально.
Как думаете, вариант с двумя hidden, в которые js-ом записывается два timestamp: один — при генерации страницы, второй — при отправке формы, на сервере высчитываем разницу — насколько жизнеспособен?
Жизнеспособен, но имхо избыточен, т.к. сервер же может получить текущий timestamp и без фронта, какой смысл его слать с фронта?
А проблем с разницей часовых поясов клиента (фронт) и сервера (бэк) не будет? Например, комментарии пользователя из Германии будут априори спамными на сайте с сервером в Японии?
Хорошее замечание! Проблемы будут — нужно заменить на GMT время.
Спасибо, отличное решение! Попробую подключить у себя в блоге, а то чистить спам порядком поднадоело.