Архив рубрики: Software

WordPress: Блокирование ботов

С января 2024 года обратил внимание, что в Яндекс-Метрика в статистике резко подскочили посещения сайта. Если присмотреться (открыть Вебвизор), то станет видно, что основная масса таких посещений идёт на главную страницу, при этом идут прямые заходы, а не через поисковые системы. Есть конечно исключения, но основная часть была именно такой. При этом, в Визоре в деталях визита было указано, что посетитель пришёл из подсети Biterika Grupp OOO. Поскольку я с рекламы на сайте едва получаю денег на оплату хостинга, то эти визиты мне подпортили и без того не очень радужную картину по доходу с рекламы. Данный сайт мне нужен не для заработка, а для сохранения какой-то информации, тем не менее я решил найти способ избавится от этой напасти.

Поиск в инете привёл меня к трём решениям (был ещё скрипт за >3000 рублей в месяц, но это не для меня):

  • Блокировка по IP через файл .htaccess.
    Описанный метод самый простой, но наименее эффективный, т.к. пул адресов ботов огромный. Тем не менее, в качестве какой-то защиты можно внести в файл пару-тройку десятков записей.

     

    .htaccess
    RewriteEngine On
    RewriteCond %{HTTP_REFERER} ^https?://([^.]+\.)*pfbaza\.website.* [NC]
    RewriteRule .* - [R=403,L]
    
    Order Deny,Allow
    Deny from 45.134.253.0/24
    Deny from 46.8.14.0/23
    Deny from 95.182.124.0/24
    Deny from 45.142.253.0/24
    Deny from 45.84.177.0/24
    Deny from 77.83.148.0/24
    Deny from 45.86.0.0/23
    Deny from 46.8.11.0/24
    Deny from 45.81.136.0/24
    Deny from 46.8.212.0/23
    Deny from 109.248.205.0/24
    Deny from 193.58.169.0/24
    Deny from 2a0e:cd42::/32
    Deny from 188.130.210.0/24
    Deny from 109.248.167.0/24
    Deny from 45.145.116.0/22
    Deny from 46.8.154.0/24
    Deny from 194.156.97.0/24
    Deny from 45.87.252.0/23
    Deny from 95.182.126.0/23
    Deny from 46.8.56.0/23
    Deny from 2a0f:d004::/32
    Deny from 46.8.16.0/23
    Deny from 2a0e:cd44::/32
    Deny from 2a0f:d000::/29
    Deny from 109.248.129.0/24
    Deny from 45.89.16.0/22
    Deny from 45.140.54.0/23
    Deny from 194.34.248.0/24
    Deny from 45.139.176.0/23
    Deny from 45.134.180.0/22
    Deny from 45.139.176.0/24
    Deny from 45.89.16.0/23
    Deny from 2a0f:d000::/32
    Deny from 188.130.187.0/24
    Deny from 46.8.10.0/24
    Deny from 46.8.22.0/24
    Deny from 45.142.252.0/24
    Deny from 109.248.55.0/24
    Deny from 212.115.49.0/24
    Deny from 45.135.33.0/24
    Deny from 2a0f:d001::/32
    Deny from 188.130.136.0/23
    Deny from 188.130.143.0/24
    Deny from 45.140.52.0/22
    Deny from 188.130.128.0/23
    Deny from 46.8.155.0/24
    Deny from 95.182.126.0/24
    Deny from 45.139.177.0/24
    Deny from 46.8.23.0/24
    Deny from 45.145.116.0/23
    Deny from 45.147.193.0/24
    Deny from 109.248.13.0/24
    Deny from 109.248.166.0/24
    Deny from 45.11.20.0/24
    Deny from 188.130.219.0/24
    Deny from 188.130.186.0/24
    Deny from 2a0b:2d87:8000::/33
    Deny from 188.130.221.0/24
    Deny from 2a0e:8146::/32
    Deny from 194.32.237.0/24
    Deny from 109.248.54.0/23
    Deny from 109.248.54.0/24
    Deny from 46.8.222.0/23
    Deny from 109.248.166.0/23
    Deny from 188.130.189.0/24
    Deny from 109.248.12.0/23
    Deny from 109.248.138.0/24
    Deny from 2a06:d647::/32
    Deny from 2a0a:b387::/33
    Deny from 188.130.220.0/23
    Deny from 46.8.57.0/24
    Deny from 185.181.244.0/23
    Deny from 46.8.156.0/23
    Deny from 84.54.53.0/24
    Deny from 2a0f:d002::/32
    Deny from 109.248.15.0/24
    Deny from 109.248.14.0/24
    Deny from 45.87.253.0/24
    Deny from 2a0e:8147::/32
    Deny from 194.156.92.0/24
    Deny from 2.59.50.0/24
    Deny from 46.8.192.0/23
    Deny from 109.248.48.0/23
    Deny from 185.181.246.0/24
    Deny from 45.84.176.0/24
    Deny from 2a0e:cd43::/32
    Deny from 188.130.210.0/23
    Deny from 91.188.244.0/24
    Deny from 194.35.113.0/24
    Deny from 2a0e:8140::/29
    Deny from 109.248.128.0/24
    Deny from 92.119.193.0/24
    Deny from 45.11.21.0/24
    Deny from 188.130.188.0/23
    Deny from 2a0e:cd46::/32
    Deny from 2a0e:8140::/32
    Deny from 45.135.32.0/24
    Deny from 188.130.218.0/24
    Deny from 188.130.184.0/24
    Deny from 188.130.184.0/23
    Deny from 46.8.56.0/24
    Deny from 185.181.247.0/24
    Deny from 188.130.186.0/23
    Deny from 109.248.139.0/24
    Deny from 188.130.142.0/24
    Deny from 46.8.106.0/23
    Deny from 2a0a:5684::/32
    Deny from 188.130.188.0/24
    Deny from 2a0e:8142::/32
    Deny from 109.248.142.0/23
    Deny from 109.248.143.0/24
    Deny from 46.8.111.0/24
    Deny from 45.139.125.0/24
    Deny from 45.140.52.0/23
    Deny from 45.15.236.0/24
    Deny from 109.248.14.0/23
    Deny from 188.130.218.0/23
    Deny from 213.226.101.0/24
    Deny from 2a0f:d006::/32
    Deny from 46.8.17.0/24
    Deny from 188.130.137.0/24
    Deny from 46.8.213.0/24
    Deny from 45.134.252.0/24
    Deny from 77.83.148.0/23
    Deny from 45.135.32.0/23
    Deny from 95.182.124.0/23
    Deny from 31.40.203.0/24
    Deny from 46.8.222.0/24
    Deny from 45.147.192.0/23
    Deny from 77.94.1.0/24
    Deny from 193.53.168.0/24
    Deny from 46.8.188.0/24
    Deny from 45.86.1.0/24
    Deny from 2a0f:d007::/32
    Deny from 45.15.72.0/24
    Deny from 46.8.223.0/24
    Deny from 95.182.125.0/24
    Deny from 109.248.138.0/23
    Deny from 2a0e:cd45::/32
    Deny from 46.8.154.0/23
    Deny from 45.15.73.0/24
    Deny from 109.248.49.0/24
    Deny from 45.87.252.0/24
    Deny from 176.53.186.0/24
    Deny from 46.8.16.0/24
    Deny from 194.156.123.0/24
    Deny from 45.134.252.0/23
    Deny from 2a0b:2d87::/33
    Deny from 109.248.204.0/23
    Deny from 46.8.107.0/24
    Deny from 109.248.128.0/23
    Deny from 45.144.36.0/24
    Deny from 194.32.229.0/24
    Deny from 45.86.0.0/24
    Deny from 185.181.246.0/23
    Deny from 46.8.156.0/24
    Deny from 2a0e:8145::/32
    Deny from 185.181.245.0/24
    Deny from 188.130.220.0/24
    Deny from 188.130.185.0/24
    Deny from 2a0e:cd40::/32
    Deny from 109.248.12.0/24
    Deny from 45.15.236.0/23
    Deny from 46.8.157.0/24
    Deny from 2a07:ca07::/33
    Deny from 2a0a:5687::/32
    Deny from 2a0e:cd47::/32
    Deny from 194.156.96.0/23
    Deny from 2a0a:5680::/29
    Deny from 2a0a:b387::/32
    Deny from 185.181.244.0/24
    Deny from 2a06:d647::/33
    Deny from 2a06:d647:8000::/33
    Deny from 46.8.110.0/24
    Deny from 95.182.127.0/24
    Deny from 2a0e:cd40::/29
    Deny from 2a0a:b387:8000::/33
    Deny from 45.142.252.0/23
    Deny from 46.8.10.0/23
    Deny from 2a0a:5680::/32
    Deny from 188.130.128.0/24
    Deny from 109.248.204.0/24
    Deny from 45.151.145.0/24
    Deny from 77.83.84.0/24
    Deny from 45.84.176.0/23
    Deny from 193.58.168.0/23
    Deny from 45.145.118.0/23
    Deny from 46.8.106.0/24
    Deny from 46.8.212.0/24
    Deny from 109.248.142.0/24
    Deny from 188.130.142.0/23
    Deny from 46.8.14.0/24
    Deny from 188.130.136.0/24
    Deny from 46.8.192.0/24
    Deny from 109.248.48.0/24
    Deny from 45.11.20.0/23
    Deny from 2a07:ca07::/32
    Deny from 45.90.196.0/24
    Deny from 2a0a:5685::/32
    Deny from 2a0a:5686::/32
    Deny from 2a0e:8144::/32
    Deny from 2a0e:8143::/32
    Deny from 46.8.15.0/24
    Deny from 94.158.190.0/24
    Deny from 194.156.96.0/24
    Deny from 46.8.193.0/24
    Deny from 45.81.137.0/24
    Deny from 192.144.31.0/24
    Deny from 45.134.180.0/23
    Deny from 77.83.149.0/24
    Deny from 2a07:ca07:8000::/33
    Deny from 2a0f:d003::/32
    Deny from 46.8.22.0/23
    Deny from 45.15.72.0/23
    Deny from 5.183.130.0/24
    Deny from 188.130.129.0/24
    Deny from 45.147.192.0/24
    Deny from 45.15.237.0/24
    Deny from 188.130.211.0/24
    Deny from 45.81.136.0/23
    Deny from 2a0b:2d87::/32
    Deny from 2a0e:cd41::/32
    Deny from 193.58.168.0/24
    Deny from 2a0f:d005::/32
    Deny from 2a0e:8141::/32
    Deny from 45.134.182.0/23
    Allow from all
  • Использование облачного сервиса Cloudflare.
    Поскольку данный метод требует, чтобы сайт был на домене второго уровня, а не третьего, как у меня, то мне этот метод не подошёл.

    Для начала небходимо заполнить форму регистрации, после чего выбрать бесплатный тарифный план и вам предложат внести у себя на хостинге новые адреса NS серверов вместо своих. Дальше уже в настройках файрвола Cloudflare нужно перейти в раздел WAF (Web Application Firewall) и внести всего одну запись:

    (ip.geoip.asnum in {35048})

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

  • Для меня оставался ещё один способ — это допилить WordPress, чтобы сделать хоть какую-то примитивную защиту от ботов.
    Решение нашёл на сайте zsay.ru, источник скрипта здесь. Этот способ я и рассмотрю ниже.

Решение для WordPress

Основные файлы и код брал с того сайта, лишь немного их изменив.

 

1. В корне сайта создаём папку detect и помещаем туда файл стилей:

/detect/welcome-pt.css
/* Modal */
.welcome-pt-overlay {
  opacity: 0;
  visibility: hidden;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background-color: rgba(0, 0, 0, .5);
  z-index: 8000;
  transition: all 0.3s;
}
.welcome-pt-message {
  opacity: 0;
  visibility: hidden;
  width: 100%;
  max-width: 500px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 8001;
  box-shadow: 0px 11px 15px -7px rgb(0 0 0 / 20%), 0px 24px 38px 3px rgb(0 0 0 / 14%), 0px 9px 46px 8px rgb(0 0 0 / 12%);
  text-align: center;
  padding: 30px;
  margin: 16px 0;
  border-radius: 4px;
  background-color: #fff;
  box-sizing: border-box;
  transition: all 0.3s;
}
@media (max-width: 532px) {
  .welcome-pt-message {
    width: auto;
    left: 16px;
    right: 16px;
    transform: translate(0, -50%);
  }
}
.is-active.welcome-pt-overlay,
.is-active .welcome-pt-message {
  opacity: 1;
  visibility: visible;
}

/* Custom styles here */
.site-form-title {
  text-align: center;
  margin-bottom: 20px;
  font-size: 36px;
  line-height: 40px;
  font-weight: 300;
  color: #3d424b;
}
@media (max-width: 532px) {
  .site-form-title {
    margin-bottom: 14px;
    font-size: 30px;
    line-height: 36px;
  }
}
.site-form-text {
  font-size: 16px;
  line-height: 20px;
  margin-top: 0;
}
.site-form-buttons {
  display: flex;
  justify-content: center;
  margin-top: 32px;
}
.welcome-pt-close {
  height: 50px;
  line-height: 50px;
  min-width: 180px;
  padding: 0 32px;
  border: none;
  font-size: 16px;
  white-space: nowrap;
  color: #fff;
  cursor: pointer;
  text-decoration: none;
  border-radius: 5px;
  background-color: #0836ff;
  transition: all 0.3s ease 0s;
  display: inline-block;
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  box-sizing: border-box;
  text-align: center;
  box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
}
.welcome-pt-close:hover {
  background-color: #0435c9;
}

2. Туда же положим файл-загрузчик скриптов pts.lazyload.js:

/detect/pts.lazyload.js
class ptsLazyLoad {
    constructor(dataLazyLoadingJS, dataSettings) {
        this.dataLazyLoadingJS = dataLazyLoadingJS;
        this.dataSettings = dataSettings;
    }
    lazyLoadingJS(type, area) {
        if (this.dataLazyLoadingJS['data'][type]['status'] === false) {
            this.dataLazyLoadingJS['data'][type]['status'] = true;

            const render = (relEl, tpl) => {
                const range = document.createRange();
                range.selectNode(relEl);
                const child = range.createContextualFragment(tpl);
                return relEl.appendChild(child);
            };
            render(area, this.dataLazyLoadingJS['data'][type]['html']);
        }
    }
    loadAllDataScripts() {
        for (let key in this.dataLazyLoadingJS['data']) {
            this.lazyLoadingJS(key, document.querySelector(this.dataLazyLoadingJS['data']['area']));
        }
    }
    showMessage() {
        let that = this;
        let modal = document.querySelector('.welcome-pt-overlay');
        let closeButton = document.querySelector('.welcome-pt-close');
        modal.classList.add('is-active');
        closeButton.addEventListener('click', function(event) {    
            event.preventDefault();  
            modal.classList.remove('is-active');
            that.cookieSet();
            that.loadAllDataScripts();
            setTimeout(function() {
                modal.style.display = 'none';
            }, 300);
        });
    }
    isSearchSystemBotSigns() {        
        let uaList = [
            'APIs-Google', 'Mediapartners-Google', 'AdsBot-Google-Mobile', 'AdsBot-Google', 'Googlebot', 'AdsBot-Google-Mobile-Apps',
            'YandexBot', 'YandexMobileBot', 'YandexDirectDyn', 'YandexScreenshotBot', 'YandexImages', 'YandexVideo', 'YandexVideoParser',
            'YandexMedia', 'YandexBlogs', 'YandexFavicons', 'YandexWebmaster', 'YandexPagechecker', 'YandexImageResizer', 'YandexAdNet',
            'YandexDirect', 'YaDirectFetcher', 'YandexCalendar', 'YandexSitelinks', 'YandexMetrika', 'YandexNews', 'YandexCatalog',
            'YandexMarket', 'YandexVertis', 'YandexForDomain', 'YandexSpravBot', 'YandexSearchShop', 'YandexMedianaBot', 'YandexOntoDB',
            'YandexOntoDBAPI', 'YandexVerticals', 'Mail.RU_Bot', 'StackRambler', 'Yahoo', 'msnbot', 'bingbot', 'PixelTools', 'PixelBot'
        ];
        let sBrowser = false, sUsrAg = navigator.userAgent;
        for (let i = 0; i < uaList.length; i += 1) {
            if (sUsrAg.indexOf(uaList[i]) > -1) {
                sBrowser = true;
                break;
            }
        }

        return sBrowser;
    }
    cookieCheck() {
        return document.cookie.indexOf(this.dataSettings.cookie_name) > -1;
    }
    cookieSet() {
        const date = new Date();      
        date.setTime(`${date.getTime()}${(365 * 30 * 24 * 60 * 60 * 1000)}`);      
        let expiryDate = `expiryDate=" ${date.toUTCString()}`;      
        document.cookie = `${this.dataSettings.cookie_name}=true; ${expiryDate}; path=/`;
    }
    simpleCheck(need_check) {
        if (+need_check === 1 && !this.cookieCheck() && !this.isSearchSystemBotSigns()) {
            this.showMessage();
        } else {
            this.loadAllDataScripts();
        }
    }
}
Здесь мы заодно проверяем посетителя и, если он «хороший» бот, то пропускаем сразу, если нет, выводится окошко с предупреждением, о том, что ведётся сбор IP-адресов. Кроме этого, скрипты Яндекс-метрики и Гугл-Аналитики загружаются только после нажатия кнопки. Ну и конечно в Яндекс-Метрику передаётся IP-адрес посетителя. Этот адрес берём с помощью нашего же сервера, а не внешнего, так что задержка будет минимальной. Его можно увидеть в дополнительной колонке Веб-Визора «Параметры визита». Для этого нужно нажать на кнопку «Настроить столбцы».

 

3. В дочерней теме WordPress нам потребуется изменить файл header.php. Здесь мы просто добавим к концу файла следующие строчки:

header.php
  <div class="before-footer-scripts-place"></div>

<div class="welcome-pt-modal">
  <div class="welcome-pt-overlay">
    <div class="site-popup-inner welcome-pt-message">
      <form method="post" enctype="multipart/form-data" action="">
        <div class="site-form-title">Добро пожаловать!</div>
        <div class="site-row">
          <p class="site-form-text">В связи с наплывом ботов приходится собирать IP-адреса каждого посетителя!Если вы с этим не согласны, просто закройте страницу.</p>
        </div>
        <div class="site-form-buttons">
          <div class="site-form-button">
            <a href="#" class="welcome-pt-close">Продолжить</a>
          </div>
        </div>
      </form>
    </div>
  </div>
</div>

<script type="text/javascript">
  var yaParams = {addr: "<? echo $_SERVER['REMOTE_ADDR']; ?>"};
</script>

<script src="/detect/pts.lazyload.js"></script>
<script>
  document.addEventListener('DOMContentLoaded', function() {
    let dataLazyLoadingJS = {
      data: {
        ya_counter: {
          status: false,
          html: '<script type="text/javascript">(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; m[i].l=1*new Date(); for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)}) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(12345678, "init", {params:window.yaParams, clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true }); <\/script> <noscript><div><img src="https://mc.yandex.ru/watch/12345678" style="position:absolute; left:-9999px;" alt="" /><\/div><\/noscript>',
          area: 'head'
        },
        ga_counter: {
          status: false,
          html: `<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456789-1"><\/script><script>function getCid(){var match=document.cookie.match('(?:^|;)\\\\s*_ga=([^;]*)');var raw=(match)?decodeURIComponent(match[1]):null;if(raw)match=raw.match(/(\\d+\\.\\d+)$/);var gacid=(match)?match[1]:null;return gacid?gacid:false;}<\/script>`,
          area: 'head'
        }
      }
    };
    let dataSettings = {
      cookie_name: 'PST_VERIFIED_COOKIE',
    };
    let LazyLoad = new ptsLazyLoad(dataLazyLoadingJS, dataSettings);
    LazyLoad.simpleCheck(1);
  });
</script>
Здесь нужно в двух местах заменить 12345678 на номер вашего счётчика, для Гугла заменить ID UA-123456789-1 на свой.

 

4. Подключение стилей для окошка делается в начале файла header.php, прямо ПЕРЕД закрывающимся тэгом </head>:

header.php
<link rel="stylesheet" href="/detect/welcome-pt.css">
Если что-то забыл, напишите в комментариях, дополню.

 

В одной из следующих заметок я описал практически 100% способ защиты от поведенческих ботов с помощью Яндекс-капчи (Smart-capcha).