Динамическая блокировка IP-адресов, маскирующихся под вредоносных Googlebot, с помощью обратного поиска DNS в fail2ban

8 min

language: ja bn en es hi pt ru zh-cn zh-tw

Привет, я Munou.
В прошлый раз
Исследование IP-адресов запросов, выдающих себя за ботов Google, включая случаи злоупотребления — SOULMINIGRIG

Здесь я подтвердил, что существует довольно много групп IP-адресов, которые отправляют запросы, маскируясь под Google.
Но как их заблокировать? Другими словами, было бы хорошо, если бы fail2ban мог обнаруживать их и запускать указанный скрипт. Подсказка нашлась в следующем issue:
apache-fakegooglebot: whitelist · Issue #1318 · fail2ban/fail2ban · GitHub

Проще говоря, мы сначала массово отлавливаем всех ботов Google, а затем с помощью специального скрипта выполняем проверку для ignoreip.
Это должно сработать.

jail.local

Добавьте следующее:


[fake-googlebot]
enabled = true
filter = fake-googlebot
port = http,https
logpath = /var/log/nginx/access.log
findtime = 1w
maxretry = 1
bantime = 99999w
ignorecommand = /usr/local/bin/check_googlebot.sh <ip>
action = pf[name=fake-googlebot]

В этом случае необходимо создать фильтр fake-googlebot.
Также потребуется шелл-скрипт, указанный в ignorecommand.

filter.d/fake-googlebot.conf

Настраиваем захват широкого диапазона следующим образом:

[Definition]
failregex = ^<HOST> - .*"(GET|POST|HEAD|PUT|DELETE|OPTIONS|PATCH) .*" \d+ \d+ ".*" ".*Googlebot.*"$
ignoreregex =

/usr/local/bin/check_googlebot.sh

В случае с ignorecommand, если при выполнении возвращается код ошибки, IP-адрес обрабатывается как объект для бана.
То есть, передавая IP-адрес в качестве аргумента и получая код состояния выполнения, можно определить, следует ли забанить адрес или пропустить его.

#!/bin/sh
IP="$1"
LOG="/var/log/check_googlebot.log"
# Обратный поиск (PTR)
HOST=$(getent hosts "$IP" | awk '{print $2}' | head -n1)
if [ -z "$HOST" ]; then
  echo "[$(date)] DENY $IP: no PTR" >> "$LOG"
  exit 1
fi
# Проверка, принадлежит ли домен Google
case "$HOST" in
  *.googlebot.com|*.google.com)
    ;;
  *)
    echo "[$(date)] DENY $IP: invalid domain ($HOST)" >> "$LOG"
    exit 1
    ;;
esac
# Прямой поиск для проверки соответствия исходному IP
MATCH=1
getent hosts "$HOST" | awk '{print $1}' | while read -r RESOLVED; do
  if [ "$RESOLVED" = "$IP" ]; then
    MATCH=0
    break
  fi
done
if getent hosts "$HOST" | awk '{print $1}' | grep -Fxq "$IP"; then
  echo "[$(date)] ALLOW $IP: valid Googlebot ($HOST)" >> "$LOG"
  exit 0
else
  echo "[$(date)] DENY $IP: mismatch ($HOST)" >> "$LOG"
  exit 1
fi

Причина, по которой я не использую команду host, заключается в том, что она не является универсальной. В системах на базе Debian она, кажется, входит в bind-utils, но я получаю PTR-запись через getent hosts, которая доступна, если установлена glibc.
[SOLVED] Host command / Newbie Corner / Arch Linux Forums

Проверка

Попробуем запустить скрипт и убедимся, что для IP-адреса бота Google возвращается 0.

# sh /usr/local/bin/check_googlebot.sh 66.249.74.78
# echo $?
0

А что, если использовать другой IP? Попробую ввести IP своего сервера.

# sh /usr/local/bin/check_googlebot.sh 163.44.113.145
# echo $?
1

Похоже, проверка работает правильно.

fail2ban

Перезапустите fail2ban, чтобы применить этот фильтр.

service fail2ban restart
fail2ban-client status 

Проверьте следующее, чтобы убедиться, что недавние IP-адреса Google не были забанены по ошибке.

# fail2ban-client status fake-googlebot
Status for the jail: fake-googlebot
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/nginx/access.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

В логах остались записи от проверки IP моего собственного сервера чуть ранее, но боты Google, судя по всему, определяются правильно.

# tail /var/log/check_googlebot.log 
[Sun Apr 19 01:58:18 JST 2026] ALLOW 66.249.74.65: valid Googlebot (crawl-66-249-74-65.googlebot.com)
[Sun Apr 19 01:58:18 JST 2026] ALLOW 66.249.74.78: valid Googlebot (crawl-66-249-74-78.googlebot.com)
[Sun Apr 19 01:58:18 JST 2026] ALLOW 66.249.74.64: valid Googlebot (crawl-66-249-74-64.googlebot.com)
[Sun Apr 19 01:58:18 JST 2026] ALLOW 66.249.74.64: valid Googlebot (crawl-66-249-74-64.googlebot.com)
[Sun Apr 19 01:58:19 JST 2026] ALLOW 66.249.74.64: valid Googlebot (crawl-66-249-74-64.googlebot.com)[Sun Apr 19 01:58:19 JST 2026] ALLOW 66.249.74.78: valid Googlebot (crawl-66-249-74-78.googlebot.com)
[Sun Apr 19 01:58:19 JST 2026] ALLOW 66.249.74.64: valid Googlebot (crawl-66-249-74-64.googlebot.com)
[Sun Apr 19 01:58:19 JST 2026] ALLOW 66.249.74.78: valid Googlebot (crawl-66-249-74-78.googlebot.com)
[Sun Apr 19 03:56:30 JST 2026] ALLOW 66.249.74.78: valid Googlebot (crawl-66-249-74-78.googlebot.com)
[Sun Apr 19 03:58:18 JST 2026] DENY 163.44.113.145: invalid domain (v163-44-113-145.v1i0.static.cnode.jp)

Однако в этом случае запрос PTR-записи будет выполняться при каждом обращении Googlebot, поэтому было бы лучше реализовать своего рода псевдо-кэширование, например, разрешать IP-адреса, которые уже имеют статус ALLOW, без повторного выполнения запроса.

Related Posts