§0入口を通り抜けてくる相手
前回の「止める場所を、手前へ」で、接続と Apache の段階で止める仕組みを整えました。それでも、PHP まで届いた記録の中には、bot が残ります。
本物のブラウザを自動で動かす相手は、形の整ったリクエストを送ってきます。UA も、普通の Chrome そのものです。入口のどの層にも引っかからず、ページまで届きます。
「bot は、3種類いる」で書いたとおり、UA は自己申告にすぎません。では、何を見ればよいのか。答えは2つありました。UA の外側の細部と、ページを開いたあとに届く合図です。
この2つを組み合わせるようになってから、ページの段階で「人」と判定した閲覧と、合図で人と確かめられた閲覧が、8割以上で重なるようになりました。この記事では、その考え方を書きます。
どのヘッダーの、どんな値を見ているかは書きません。判定の中身を書けば、相手にとっての手直しの手順書になるからです。食い違いの「種類」と、組み合わせ方の考え方を中心にします。
§1ブラウザが自動で作る細部
ブラウザが1回のリクエストで送るのは、UA だけではありません。どの言語を読みたいか、どんな種類の読み込みか、ブラウザの種類と版をもう一度伝えるヘッダー(Client Hints)など、いくつもの情報が一緒に届きます。
これらは全部、同じブラウザのエンジンが、自分の決まりに従って作っています。人が1つずつ選んでいるわけではないので、本物なら、必ず揃います。
道具を作る側は、目に見える UA は本物そっくりに書き写せます。けれども、ほかのヘッダーまで、そのブラウザの決まりどおりに揃えるのは手間がかかります。どこか1か所で、別のブラウザの癖が混ざります。
食い違いの種類
| 食い違い | たとえるなら |
|---|---|
| 名乗った版と、別のヘッダーが示す版が違う | 名刺と社員証で、会社名が違う |
| その版なら必ず送るはずのものがない | 制服を着ているのに、名札を付けていない |
| 別のブラウザの書き方の癖が混ざる | 標準語で話しているのに、ところどころ別の地方の言い回しが出る |
| 今のブラウザがもう書かない書き方をしている | とうに変わった古い住所の書き方のまま |
広く知られた例を1つだけ挙げます。Safari を名乗っているのに、Chromium の版を伝える Sec-CH-UA を送ってくる相手です。Safari はこのヘッダーを送りません。送ってくるのは、中身が Chromium だからです。UA だけを iPhone の Safari に差し替えた、自動操作のブラウザによく見られます。
裏の名札に、自分で書いていた
ある道具は、毎回2段階でトップページを取りに来ていました。1回目は HTML だけの単純な取得で、1分ほどあとの2回目は、本物のブラウザで描画しています。表の UA は iPhone の Safari でしたが、2回目の裏の名札(Client Hints)には、「headless の Chrome」とそのまま書いてありました。
手間をかけた道具ほど、どこかで本当の中身が見えます。表を本物に似せるほど、裏との食い違いが目立つのです。
§2ビーコン:人である証拠
細部の食い違いは「bot らしさ」の証拠です。逆に、「人らしさ」の証拠も欲しくなります。それがビーコンです。
ページに小さな JS を置き、読み手がしばらくページを見ていたときか、画面に触れたときに、1回だけ合図を送ります(navigator.sendBeacon)。合図は記録の1件ごとに結びつけてあり、届いたら、その記録に印を付けます。
人のブラウザは JS を動かすので、合図が来ます。HTML だけを取りに来る道具からは、来ません。
判定と合図の、4つの組み合わせ
ページの段階の判定(bot か、人か)と、合図の有無を組み合わせると、記録は4つに分かれます。
ログ一覧では、この組み合わせをバッジで並べて表示しています。1件ずつ眺めるだけで、どこに迷いがあるかが分かります。
合図があっても、人とは限らない
本物のブラウザを裏で動かす道具は、JS も動かします。ですから、合図は来ます。§1 の2段階の道具も、2回目には合図が届いていました。
ただ、そうした合図には、画面に触れた跡がありません。時間がたったことで送られた合図だけが並びます。とはいえ、読むだけで画面に触れない人もいるので、触れた跡がないことだけを理由に bot とは決められません。
だから、合図は単独では使いません。「細部が揃っていて、合図も来た」ときに、はじめて人として数えます。bot らしさの証拠と、人らしさの証拠を、両方から見るのが基本です。
§3どちらでもないもの
ログを1件ずつ見ていくと、bot とも人とも言い切れない記録が出てきます。無理にどちらかへ入れると、数字がゆがみます。
先読み
Chrome は、検索結果の上位のページを、読み手が押す前に先回りして取りに来ることがあります。Google 検索からの先読みは、Google の中継を通って届きます。このとき、リクエストには Sec-Purpose: prefetch が付いています。
読み手がそのあと結果を押すと、ブラウザは先に取っておいたものを表示します。サーバーには2回目のリクエストが来ません。記録は先読みの1件だけで、そこに合図が届けば「開かれた」、届かなければ「空振り」です。
- 先読みの記録の IP は、読み手ではなく中継のものです。IP をもとにした判定は、当てはめないように気をつけます。
- アドレスバーに文字を打ち始めたときに、裏で描画まで済ませておく先読みもあります。こちらは、一度来たことのある人の再訪のしるしになります。
- ログ一覧には、先読みの印(PF・PR)を出すようにしました。
アプリの中の、一瞬の表示
UA の末尾に Safari の名前がない iPhone や iPad からの記録が、合図なしで並んでいたことがありました。アプリが自分の中にページを表示する部品を使ったときの UA です。
Apache のログを並べると、HTML のあとに CSS も JS も読み込まれていて、JS が別の通信を始めた跡までありました。それなのに、合図の送り先にだけ来ていません。つまり、合図を送る前に閉じられていました。最初のリクエストは、昔の http:// のリンクからの転送でした。どこかに保存された古いリンクの、見た目づくりのための読み込みでしょう。
これは bot ではありません。けれども、人が読んだとも言えません。「確かめられない」のままにしておくのが正しい扱いです。合図の条件を緩めれば数字は増えますが、それは見た目の数字です。
HTML しか取りに来ない → 道具。CSS・JS まで読むのに合図が来ない → 一瞬の表示。合図の送り先まで届く → 人の閲覧。この3つは、Apache のログを並べるだけで見分けられます。
古いブラウザのまま使う人
古い版のブラウザは、bot がよく名乗る形でもあるので、ページの段階では bot と判定します。ところが、その中に人がいました。会社が管理するクラウドのブラウザ環境から、版が止まった Chrome で、表計算のページを繰り返し見ている人です。
そこで、いったん bot と判定した記録でも、人の証拠が揃えば、あとから人に戻すようにしました(救済)。
ここで、もう1つ問題が見つかりました。bot と判定した記録には、毎回新しいセッションの印を付けていたのです。そのため、救済された人は、1ページごとに別の人として数えられていました。2回の訪問が、8つのセッションになっていました。戻す仕組みを作ったら、数え方も一緒に直す必要がありました。
§4判定を重ねる
1つ直されても、ほかが残る
道具の作者は、捕まると原因を1つずつ直してきます。UA を変え、足りないヘッダーを足し、版を揃える。1つの食い違いだけで捕まえていると、それを直された時点ですり抜けます。
いくつもの独立した食い違いで、同時に捕まえるようにしておけば、1つ直されても、ほかが残ります。そのために、判定の理由は1つ目だけでなく、当てはまったものを全部、記録に残しています。
守りの薄いところを数える
理由を全部残しておくと、「理由が1つだけで捕まっている記録」を数えられます。そこが、守りの薄いところです。
とくに、合図が届いているのに、理由が1つだけの bot。本物のブラウザを動かす相手が、たった1つの食い違いで捕まっている状態です。その1つを直されれば、そのまま「確かめられた人」の側へ移ってしまいます。数字にいちばん直接響くので、定期的に数えて、別の角度からも捕まえられるように備えます。
大まかな方針は、ヘッダーの整合性で大半をふるい落とし、残りは振る舞いで確かめる、という二段構えです。ヘッダーがすべて本物の相手でも、どう渡り歩くかには、人とは違う形が出ます。
足す前に、人を数える
新しい判定を思いついたら、足す前に、その形に当てはまる過去の記録のうち、合図で人と確かめられたものが何件あるかを数えます。0件のときだけ足します。
1件でもあれば、その人の記録を見に行きます。古い版のまま使う人や、会社の管理する環境から使う人がいることがあります。実際、ある候補は「版で線を引く」形でしたが、少し古い版に人が何人かいたので、取りやめました。
足した判定と見送った判定は、日付、きっかけ、確かめた結果と一緒に、手元の台帳に1行ずつ残しています。公開しない台帳です。
§5デモ:記録を仕分ける
例の記録を8枚並べました。それぞれを「人」「bot」「決めない」のどれかに仕分けてください。押すと答えと理由が出ます。項目は、実際のヘッダーではなく、この記事の言葉に置き換えてあります。
§6まとめ
- UA は自己申告。見るのは、UA の外側の細部が、そのブラウザの決まりどおりに揃っているかどうか。
- 合図は、人らしさの証拠。ただし単独では使わず、細部の整合と組み合わせる。
- 二択で割り切らない。先読み、一瞬の表示、古いブラウザの人。「決めない」と「あとで戻す」を用意しておく。
- 判定は重ね、薄いところを数え、足す前に人を数える。
こうして、ページの段階で「人」と判定した数字を、信頼できるようになりました。数字を信頼できると、bot を除くことそのものより、その先に見えるもののほうが面白くなります。
次回は、その数字から見えてきたものを書きます。1件では分からない動きを、あとからどう拾うか。そして、人がページをどう使っているか、です。
- 止める場所を、手前へ
ipset・.htaccess・410 - UA の外側で、見分ける(この記事)
細部の整合・ビーコン・どちらでもないもの - 数字を信頼できて、見えたもの
見直し・確かめ・見張りと、人の動き