IP посетителя в Яндекс Метрике (2024 г.)

Приветствую! Сегодня я расскажу, как модифицировать Метрику, чтобы видеть ip-адреса посетителей. Делать мы это будем с целью защиты от ботов.

Также мы получим IP за прокси, точный город, страну, название провайдера и список IP, с которых он заходил ранее.

Стандартный общеизвестный метод

Вообще, давно описан и широко известен способ с передачей через $_SERVER[‘REMOTE_ADDR’] в js-переменной в коде сайта. Как-то так:

<!-- Yandex.Metrika counter -->
<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)};

    <... остальной код метрики ...>
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/123456789" style="position:absolute;left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->

<!-- наше внедрение -->
<script>
    (function(){
        var params = {
            "ip": <?=$_SERVER['REMOTE_IP']?>,
        };
        ym(123456789, 'params', resp);
    }());
</script>

Иными словами, каждый раз при посещении мы прописываем в код страницы актуальный IP пользователя.

Минусы решения

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

Есть вариация данного метода, суть в том, чтобы запросить данные по текущему IP со стороннего сервиса — например, он описан тут. Минус его в том, что если у пользователя активен блокировщик рекламы, с высокой долей вероятности домены ip-чекеров занесены в его список под заголовком «трекеры», и запрос не уйдёт. Соответственно, инфу мы не получим.

Предлагаемый метод

Мы будем использовать решение MetrikaSypexGeo ( https://github.com/HDDen/MetrikaSypexGeo ).

Вкратце, это связка Sypex Geo с сервисом ipgeolocation.io.
На бэкенде разворачивается папка с модулем, на фронт встраивается небольшой js-скрипт, который осуществляет запрос к нему. В ответ прилетает:

  • IP пользователя
  • IP за прокси
  • Город/регион/страна, на основании базы Sypex Geo
  • Имя провайдера интернета нашего посетителя (запрос к ipgeolocation.io, нужен бесплатный api-ключ)
  • Список IP посетителя на данном устройстве, с которыми он заходил на сайт (если наш спамер подключается через VPN)

Его преимущества

  1. Проброс не только прямого IP, но и доп. данных
  2. Выше точность определения локации пользователя
  3. Минимальное влияние на производительность сайта
  4. Отсутствие зависимости от наличия блокировщика у посетителя
  5. Возможность сбора и автоматической блокировки IP провайдера

Пройдёмся по каждому пункту.

Передача в Метрику сопутствующих данных

Кроме передачи самого IP, скрипт пытается получить IP за прокси ( $_SERVER['HTTP_X_FORWARDED_FOR'] и $_SERVER['HTTP_CLIENT_IP'] ), и, для удобства, подсети (обрезает IP до вида 1.2.3.xx и 1.2.xx.xx). Также логирует в localstorage браузера список IP, с которыми пользователь заходил на сайт.

Более точное определение местоположения

Скрипт использует Sypex Geo для определения города посетителя.
Время от времени бывает так, что Метрика не может показать город, ограничиваясь регионом, либо еще хуже — сужая до страны. На этот случай мы дублируем определение локации по IP, получая город, регион, страну из локальной базы Sypex Geo. База обновляется по cron, нужно настроить соответствующее задание на сервере на запуск sxgeo_update.php.

Также Метрика может показывать не совсем верную локацию. Пример ниже — посетитель зашел через Германию (либо VPN, либо бот), а Яндекс решил, что он из Тулы. Возможно, само устройство действительно находилось в Туле, и Яндекс как-то это понял, но на всякий случай хорошо бы зафиксировать прямой город, из которого поступил запрос.

Влияние на производительность сайта

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

Тело скрипта обёрнуто в DOMContentLoaded, но это можно отключить, если требуется запуститься поскорее:

Независимость от блокировщиков рекламы/трекеров

В известных методах, если IP клиента не пробрасывался в тело страницы, осуществляется запрос к какому-нибудь сервису геолокации, вроде ipinfo.io или похожим, в ответ получим json с самим IP и какой-то краткой инфой по нему. Но есть проблема: это не будет работать, если у клиента установлен плагин блокировки рекламы (adblock, ublock, и т.д.) и домен этого сервиса включен в список фильтруемых. В данном случае, никакого запроса мы не отправим.

В описываемом новом способе основная информация (ip, локация, прокси) тянется из локальной базы и самого запроса, обращение идет к php-обработчику в рамках домена сайта. Подключение к стороннему сервису тоже присутствует, но это нужно только для доп. данных и можно беспрепятственно отключить либо выбрать:

  1. запрашивать доп. данные со стороны клиента (с фронта) через ipinfo.io
  2. запрашивать с бэка по API через ipgeolocation.io (необходим бесплатный ключ, даётся после регистрации)

Сторонний сервис нужен только если мы хотим передавать в Метрику ISP, т.е. провайдера интернета посетителя.

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

Автоблокировка конкретных провайдеров (на примере Biterika)

Ситуация: Валят боты из подсетей Selectel, Biterika, Hetzner. Т.к. их пул IP заранее не известен, небезопасно использовать чьи-то наработки по составлению списка IP этих провайдеров. Вместо этого мы создаём список «запрещённых» провайдеров, в котором пишем их названия в виде, котором они присутствуют в whois-базах. Далее, при ajax-запросе юзера к нашему обработчику, мы берём его IP, получаем ISP по API ipgeolocation.io, и если он из списка запрещённых — создаём файл-маркер, благодаря которому веб-сервер в следующий раз уже не пустит на сайт посетителя с этим IP/из этой подсети.

Работа последнего механизма (именно блокировка веб-сервером) строится на Apache и нуждается в редактировании .htaccess:

RewriteEngine On
RewriteBase /
RewriteCond %{REMOTE_ADDR} ^([0-9]{1,3})\.
RewriteCond %{DOCUMENT_ROOT}/madmen-includ/MetrikaSypexGeo/firewall/%1/%{REMOTE_ADDR} -f
RewriteRule . - [F]
## блок по подсети 1.2.3.* - вариант на файлах (активен)
# RewriteCond %{REMOTE_ADDR} ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})
# RewriteCond %{DOCUMENT_ROOT}/madmen-includ/MetrikaSypexGeo/firewall/%1/%1\.%2\.%3 -f
# RewriteRule . - [F]
## блок по подсети 1.2.3.* - вариант на папках (не активен)
# RewriteCond %{REMOTE_ADDR} ^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})
# RewriteCond %{DOCUMENT_ROOT}/madmen-includ/MetrikaSypexGeo/firewall/%1/%1\.%2/%1\.%2\.%3 -d
# RewriteRule . - [F]
## блок конкретных диапазонов вручную
# RewriteCond %{REMOTE_ADDR} ^1\.2\.3\. [OR]
# RewriteCond %{REMOTE_ADDR} ^1\.2\.
# RewriteRule . - [F]

Я на своих проектах использую «блок по подсети 1.2.3.* — вариант на файлах». По умолчанию код выше блокирует только посещения с точных IP.

Есть и минус — пока не реализована перепроверка имеющихся заблокированных IP и подсетей через некоторый промежуток времени, во избежание устаревания правила. Чтобы очистить список правил, нужно удалить содержимое папки /firewall/ в папке модуля.

К делу: установка и настройка

Скачивание и распаковка

Либо переходим на страницу проекта в GIT и качаем zip-архив репозитория, либо выполняем git clone https://github.com/HDDen/MetrikaSypexGeo.git .

Получившийся набор файлов размещаем в удобном месте в пределах публичной части сайта. Устанавливаем права 0755 + владельца.

Настройка путей

Следующий шаг — нужно указать актуальный путь к папке модуля. Достаточно это сделать в двух файлах: example.js (url php-обработчика, куда скрипту стучаться) и block_by_isp.php (если будет использоваться блокировка по названию провайдера)

example.js:

/hdden-includes/MetrikaSypexGeo/ipinfo.php заменить на ваш

block_by_isp.php:

Аналогично, заменить /hdden-includes/MetrikaSypexGeo/ на актуальный вариант

Первичное обновление базы Sypex Geo

За обновление базы «IP <> геолокация» отвечает файл sxgeo_update.php. Достаточно обратиться к нему по его url.

Внимание! В целях безопасности рекомендуется установить в нём ключ и передавать его в запросе в get-параметре «?secret», например https://example.loc/hdden-includes/MetrikaSypexGeo/sxgeo_update.php?secret=asewrt324534fdg

Настройка автообновления

Для автообновления достаточно повесить на cron выполнение скрипта sxgeo_update.php

Настройка параметров модуля

ipinfo.php:

$sypex_path = путь к файлам Sypex-части (сама база и скрипт для запроса к ней)
$ipgeolocationIo_tokens = массив api-ключей к сервису ipgeolocation.io
$allow_cors = возможность включить cors в случае необходимости междоменных запросов
$detect_isp = опция запроса ISP с бэкенда через ipgeolocation.io. В случае удачи передаёт его на фронт
$block_by_isp = опция блокировки по ISP. Если true, и имя провайдера присутствует в файле block_by_isp.txt, будет создавать файл-маркер для блокировки апачем следующего посещения с этого IP/подсети
$block_by_org = то же, что и $block_by_isp, но проверка идёт по другому полю ответа ipgeolocation.io
$pass_blockCheck_result = передавать ли на фронт (и в Метрику) информацию о том, что данный IP будет заблокирован
$log_before_send = логировать ли вычисленные отправляемые на фронт данные
$optimize_log = оптимизация лога; не писать заголовок к каждому обработанному запросу
$log_static_header = если заранее известен состав и порядок вычисляемых данных, записать первой строкой лога этот заголовок
$logfile = имя файла лога
$log_headers = логировать заголовки запроса посетителя к скрипту, используется для дебага

sxgeo_update.php:

$allowed_secret = если установить, все запросы к скрипту будут требовать передачи этого значения через ?secret=

example.js

metrika_id = id счётчика метрики. Если не указано, вычислится автоматически
search_isp = запрос названия провайдера через ipinfo.io (если не удалось узнать его на бэке)
storeInWindow = можно сохранить итоговый объект с вычисленными данными в window по указанному в параметре ключу

Блокировка ботов по ISP

  1. Собрать имена «надоедливых» провайдеров. Взять их можно из накопленных данных в Метрике, в параметрах визитов по ключам ip_isp и ip_org ;
  2. Внести список в block_by_isp.txt. Например, в нём уже прописаны вариации наименования Битерики;
  3. В файле ipinfo.io перевести в true параметры $block_by_isp, $block_by_org ;
  4. Скопировать из block_by_isp.php фрагмент кода для apache, вставить его в .htaccess в корне сайта, при необходимости — скорректировать пути.
    По-умолчанию код блокирует точные IP, если нужна блокировка по подсети — раскомментируйте блок по подсети 1.2.3.* - вариант на файлах (активен)
    Правила для блокировки по подсети

Установка JS-части на сайт

Открываем example.js, копируем из него фрагмент js-кода (человекочитаемый или минифицированный, в конце файла). При необходимости, настраиваем параметры и убираем загрузку по DOMContentLoaded. Вставляем на сайт либо инлайново в тег <script></script> , либо в подключаемый внешний js-файл.

Заключение

Благодарю за уделённое внимание и проявленный интерес к статье! Надеюсь, изложенная информация окажется полезной и пригодится в будущем 🙂

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх