2022-09-30追記: この記事の後にGoogleがGooglebotの範囲を公開したので、もっと簡単に簡易検証できるようになっています。
Facebookと傘下が死んでいたようですがこの記事の
Internet providers usually update their DNS records every few hours, but they can take several days to fully propagate.
はちょっと何言ってるか良く分かりませんでした。他人のRRをプロバイダがアップデートしている??? いずれにせよ全部の権威サーバ[abcd].ns.facebook.comがAS32934の中にいてサービスを提供しているサーバごとBGPテーブルから消え去ったのでネガティブレスポンスのキャッシュではなくてサーバに到達できないというエラーのキャッシュになります。キャッシュが1000くらい直列になった謎沼の底でもない限り数日かかることはないかと思います。
それはともかく本題のGooglebotの検証方法は公式には
となっています。User-agentも逆引き(rDNS, PTR RR)も詐称したい側が容易に詐称可能です。.google.com や .googlebot.com のA RRやAAAA RRはGoogleの権威サーバを乗っ取るかどこぞのキャッシュサーバを攻略しないといけないため通常は正しい、GoogleはUser-agent詐称しない、という前提のもと検証できることになります。
Apache HTTPDでは HostnameLookups Double と SetEnvIf を組み合わせて検証できます。nginxではNginx HTTP rDNS moduleを使ってできそうです。パッケージになっているディストリビューションが少ないので、配置しなければいけないサーバが多い場合はテスト目的以外で使うにはちょっと躊躇します。
そこでFCrDNS部分をざくっと省略版にしてAS番号で処理することにします。
そもそもFCrDNSでは接続一つにつきPTR RRを検索し、あった場合は接続元IPアドレスに応じてAまたはAAAA RRを検索するので処理時間のコスト高めです。Apache HTTPDの場合はUser-agentに応じてとかできないですし、公式でも負荷のかかるサーバでは逆引きも検索しないOffにするべきとなってます。
IPアドレスからAS番号にするにはRIR statsから自分で作るとか、誰かが作ってくれたマップFree IP address to ASN databaseをさらに整形して使うとか考えられます。今回はGeoLite2を使ってみます。利用にはEULAに同意する必要があります。また商用再配布の場合は別の条件が付きます。
nginx.confの概要は次のようになるので、よきにまとめてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
... load_module "/usr/local/libexec/nginx/ngx_http_geoip2_module.so"; ... http { # mmdblookup --file /usr/local/share/GeoIP/GeoLite2-ASN.mmdb --ip 8.8.8.8 autonomous_system_number geoip2 /usr/local/share/GeoIP/GeoLite2-ASN.mmdb { auto_reload 72h; $geoip2_as autonomous_system_number; } map $geoip2_as $_asg { default "unknown"; 15169 "Google"; #11344 "Google"; #... } } |
AS番号は15169だけにしてます。false negativeが発生する場合はASセットを参考にしてください。1週間ほど観察した分では、本物はすべて15169からきてました。GCP上の偽物がはじけていなかったので、Google Cloudのアドレス範囲を探します。Obtain Google IP address rangesにCloudのお客様が使える範囲へのリンクが見つかります。JSONなので整形します。
1 |
jq -r '.prefixes[] | ( .ipv4Prefix?, .ipv6Prefix? ) // empty' cloud.json | aggregate-cidr-addresses | sed -E -e 's/$/ "gcp";/' >hogehoge |
これをもうちょいいかした感じ(エラーの際は何もしないとか、最後に出来上がりをmvするとか)にして1日一回程度動かせばよさそうです。aggregate-cidr-addressesはこちらを参考にしてください。あるいはFireHOLのiprangeが引き算もできてすごく使いやすそうなので、いつか試そうと思っててのびのびです。超使えるはず。
出来上がったこのファイルを利用してnginx.confに追加します。$asgにGoogleかGooglegcpが入るようになり、$asgがGoogleではないGooglebotのUser-agentでは$crawler_fakeに1が入るようになります。fakeの場合は444でも404でも返してあげれば終わりです。しばらくは関係ない人をはじいてないことを確認します。Bingbot他も同様に追加していけるような書き方をするとこんな感じでしょうか。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
... load_module "/usr/local/libexec/nginx/ngx_http_geoip2_module.so"; ... http { # mmdblookup --file /usr/local/share/GeoIP/GeoLite2-ASN.mmdb --ip 8.8.8.8 autonomous_system_number geoip2 /usr/local/share/GeoIP/GeoLite2-ASN.mmdb { auto_reload 72h; $geoip2_as autonomous_system_number; } map $geoip2_as $_asg { default "unknown"; 15169 "Google"; } geo $asg_override { default ""; include ...../hogehoge; } map $_asg$asg_override $asg { "~^(.*)$" $1; } map $http_user_agent $_crawler_ua { default ""; "~*\b(?<!like\s)(?:APIs-Google|Mediapartners-Google|AdsBot-Google|Googlebot|FeedFetcher-Google|Google-Read-Aloud|DuplexWeb-Google|Google Favicon|googleweblight|Storebot-Google)\b" "Google_UA" } map $_crawler_ua%$asg $crawler_fake { default 0; "~^Google_UA%Google$" 0; "~_UA%" 1; } ... server { ... if ($crawler_fake = "1") { return 404; } ... } } |