fail2banで悪質なGooglebotに偽装しているIPを逆引きして動的に遮断する
こんにちは、無能です。
前回
Googleからのbotを自称するリクエストIPを悪用含めて調査 - SOULMINIGRIG
こちらで Google に偽装してリクエストするIP郡はそれなりにあることを確認しました。
しかしこれらをブロックするには?つまりは fail2ban 側で検知して指定のスクリプトを動かせればいいわけですが以下の issue にヒントがありました。
apache-fakegooglebot: whitelist · Issue #1318 · fail2ban/fail2ban · GitHub
わかりやすく言えば広域に Google のBotを拾う、その後に指定スクリプトで 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 の場合は実行時に失敗のステータスコードを受け取ることでban対象としてハンドルされます。
つまりは引数にIPアドレスを与えその実行時のステータスコードを受け取ることでBan判定と、スキップ対象かを判定出来るのです。
#!/bin/sh
IP="$1"
LOG="/var/log/check_googlebot.log"
# 逆引き
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 に含まれるようですが glibc が入っていれば使える getent hosts からPTRレコードを取得します。
[SOLVED] Host command / Newbie Corner / Arch Linux Forums
確認
試しに実行してみて、GoogleのBotのIPで戻りが 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のIPでbanされてないことを確認します。
# 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 のbotは判定されていそうでした。
# 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)
但し、この場合Googlebotからのリクエストがある度にPTRレコード問い合わせが行われる用になってしまうため問い合わせ前に ALLOW であるIPに対しては問い合わせせずに許可対象にする等の疑似キャッシュのようにしたほうがよさそうです。