昨天我們拆解了 AI 流量的三種行為。今天我們要來摧毀一個更基礎的信任前提:你憑什麼相信門外那個自稱 GPTBot 的真的是他?
答案很殘酷:你根本不知道。log 裡那欄叫做 User-Agent 的東西,純粹是對方自己填寫的搭訕台詞。沒有簽章,沒有憑證,沒有任何人幫他背書:
curl -A "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot" \
https://你自己的站/
這筆請求會大搖大擺走進你的伺服器,被大部分的報表軟體算成一次 OpenAI 的造訪,然後長在你「本週 AI 爬蟲」那張圖表的 OpenAI 柱狀圖上。從數據表面來看,他跟真正的 GPTBot 毫無破綻。因為那些分類器從頭到尾只看了他遞過來的名片。我們自己的分類器也是用正規表達式去比對 UA,字串對了就放行,廠商名稱直接抄註冊表。這中間根本沒有人停下來質問一句:「這個位址真的屬於這家公司嗎?」
今天我們要補上的,就是那段被草率跳過的信任查核:在對方的「片面宣稱」與「真實身分」之間,到底有什麼東西是可以當作鐵證的。
Cloudflare 在他們「已驗證機器人」的文件裡,把查勤的方法濃縮成了一句話(官方原話):
「Honest self-identification : it declares who it is deterministically, through a cryptographic Web Bot Auth signature, a published IP list with a stable user-agent, or reverse DNS.」
簽章 (Web Bot Auth) 是未來最完美的解答,這我們留到系列後面單獨聊。今天先談現在就能用的兩招,外加一條側面打聽的線索。這裡有個底線:這三條線索絕對不能被偷懶攪和成一個總分。
OpenAI、Anthropic、Perplexity、Google 都公開了自家爬蟲出沒的網段,通常是一份 JSON 檔案。在我們手上的爬蟲註冊表裡有 246 個條目,其中 46 個帶有官方 IP 清單的網址,涵蓋了 15 家公司。把清單抓下來,看看對方是不是從這個地址來的,聽起來很簡單對吧。
但如果你真的去翻那些檔案,你會發現三件官方絕對不會主動告訴你的殘酷現實(這是我在 2026-09-06 當天查勤抓檔的所見所聞):
一、新鮮度差很多,而且檔案自己會告訴你。 OpenAI 的 gptbot.json 裡有個 creationTime 欄位,數值停在 2025-10-30T11:00:00.000000,這已經是快十個月前的舊名單了。而 Anthropic 的 bots.json 則是 2026-08-18T23:56:36Z,不到三週前剛更新。同樣叫做「官方公布的 IP 清單」,一份是上個月的熱乎承諾,另一份根本是去年的歷史陳跡。
二、多數清單沒有 IPv6。 gptbot.json 裡那 21 個項目清一色全是 ipv4Prefix。Anthropic 的 26 個項目也全都是 IPv4。如果對方是從 IPv6 找上門的,這條線索直接作廢。這不是把對方判成騙子,是系統根本無從查證。如果你的網站開了 IPv6,而你的驗證管線沒有把這種情況老實標示為「未知」,那你就會系統性地冤枉一票 v6 流量。
三、顆粒度不一定是量身打造的。 OpenAI 乖乖把名單切成四份 (gptbot / chatgpt-user / searchbot / adsbot),對上 IP 你就知道門外站的是哪一個分身。但 Anthropic 給的卻是一份大鍋炒的合併清單,不分爬蟲種類,也沒有 UA token。這意味著命中清單只能證明「他確實是 Anthropic 的人」,卻無法證明「他是來抓資料的 ClaudeBot 還是代客跑腿的 Claude-User」。而這兩種身分在 robots.txt 裡的待遇是天壤之別的(這點明天會深聊)。
最要命的極限是:這些清單是會悄悄搬家的。所以當一個位址「不在清單裡」時,你唯一能推論的真相只有一個:
「在我們讀到的那份清單裡,找不到這個位址。」
這句話描述的是你手上的名單不夠新,而不是指控對方的來歷造假。
這不是文青在咬文嚼字。我們自己曾經兩次從「自家探測器被擋」就武斷推論「客戶網站的爬蟲進不去」。兩次都大錯特錯。把自己的處境當成全世界的真相,是感情和技術裡最常犯的毛病。
Anthropic 自己在同一頁也留下了反向的警告(原話):
「Alternate methods like blocking IP address(es) from which Anthropic Bots operates may not work correctly or persistently guarantee an opt-out」
理由很簡單,你把他的 IP 封了,他連你門口的 robots.txt 都看不到。請把這句話刺在心上:IP 清單是拿來「相認」的,不是拿來「封殺」的。
Google 的官方文件把動機寫得無比寫實(原話):
「This is useful if you're concerned that spammers or other troublemakers are accessing your site while claiming to be from Google.」
看見了嗎:「claiming to be from Google」 (宣稱自己是 Google)。這是整篇文章的靈魂,而且是廠商自己承認的。
查勤的步驟有三段:
googlebot.com)。這第三步才是整個查核機制站得住腳的關鍵。任何人都可以把自己的 IP 反解指向 crawl-foo.googlebot.com,因為反解是由位址持有者自己設定的。但全世界只有 Google 能讓那個網址正解回那個位址,因為正解的權力握在網域持有者手裡。兩邊的說法完全吻合,這段關係才算過關。
比對主機名稱的時候有個必踩的陷阱:請嚴格檢查網域邊界。evil-googlebot.com 不是 googlebot.com,x.googlebot.com.attacker.net 更是來騙人的:
// 這是對的防守
h === domain || h.endsWith(`.${domain}`)
// 這是錯的,而且它會默默放任別人劈腿
h.includes(domain)
FCrDNS 最大的悲哀在於它的覆蓋率。這招要求廠商願意公開 PTR 網域,但願意這麼坦蕩的少之又少。我們的系統裡只敢寫死兩家:google (包含 googlebot.com / google.com / googleusercontent.com) 與 microsoft (search.msn.com)。一份 IP 清單不等於一份 PTR 網域宣告,要新增一家查核對象,你就得親自去讀那家的驗證頁面,絕對不能從 IP 清單去瞎猜。
我在 2026-09-06 那天把 OpenAI、Anthropic、Perplexity、Google 四家的官方爬蟲文件從頭到尾翻了一遍。結果讓人心寒:四家都公開了 IP 清單,但只有 Google 給了反向 DNS 驗證的教學,也只有 Google 坦白承認「有人會冒充我」。三家 AI 廠商的文件裡完全沒有驗證章節,沒有任何一家願意寫下「我們的 UA 可以被偽造,請務必驗證 IP」這種提醒。
這個沉默本身就震耳欲聾:你手邊最完整、最教你怎麼保護自己的「防詐騙指南」,居然是來自一家根本不做生成式爬蟲的老牌搜尋引擎。
ASN 是 IP 網段在網路世界裡的戶籍地。查一個位址的 ASN,你就會知道他到底住在哪裡:是高大上的 AWS、GCP 公有雲,廉價的機房代管,還是普通的家庭寬頻 ISP。
ASN 只是旁敲側擊的佐證,不是一槌定音的判決。它沒辦法回答「這到底是不是 OpenAI」,因為 AI 爬蟲幾乎都租用公有雲,一個 AWS 的位址今天可能被 AI 公司包下,下週就換成某個不知名的新創。但它非常擅長戳破另一種謊言:這波流量的氣質到底像不像活人? 一波自稱是正常瀏覽器的流量,如果兩百多個 IP 全都擠在冰冷的機房和跳板網段,住宅區 ISP 的數字掛零,那這絕對不是「一群熱情的使用者」。這種殘酷的真相 ASN 說得出口,光看 IP 卻是看不出來的。
很多人以為查 IP 的 ASN 必須花錢買 API 或是註冊一堆帳號。根本不用。iptoasn.com 提供了一份 ip2asn-combined.tsv.gz,授權條款清清楚楚寫著 「Licensed under Public Domain (PDDL v1.0)」。這是公有領域的宣告,不需要帳號,不用標示出處,沒有使用範圍限制,拿去商用也毫無問題。發布方甚至明講了,讓你下載離線快照就是他們預期的玩法。資料來源是 RouteViews,上面標示著 「Updated hourly.」 格式是純粹的五欄 TSV (range_start / range_end / AS_number / country_code / AS_description),壓縮後只有 9 MB。
我實際把它倒進 Postgres 資料庫裡秤過斤兩:
| 檔案內總列數 | 717,360 |
| 有路由 (AS 不等於 0) 且實際保留 | 578,010 (其中 IPv4 有 456,233,IPv6 有 121,777) |
| 無路由被丟棄 | 139,350 |
| 格式錯誤 | 0 |
| 相異的 AS 名稱 | 86,886 |
| 範圍表落地佔用 | 52 MB (包含主鍵) |
| 名稱表落地佔用 | 7 MB |
| 單次查詢效能 | 主鍵反向索引掃描,動用 7 個 buffer,只需 0.14 ms |
你只要付出 59 MB 的硬碟空間,就能換來一套完整、不需要看任何人臉色的離線 ASN 查詢能力。不用依賴外部服務,不用管速率限制,也不用煩惱帳號過期。這門檻低得遠超乎大部分人的想像。
這裡我刻意做了一個取捨:解析時我把國別欄位直接刪了。這不是用來抓地理位置的工具,留著這個欄位,遲早會有人拿它去編造一些 ASN 根本無力背書的謊言。
在一個 30 天的觀測期內,我們抓出一批自稱是 Googlebot、但 IP 卻落在 Google 公布範圍之外的訪客。這群騙子的相異 IP 數量,是乖乖待在範圍內的真 Googlebot 的 83 倍。
83 比 1 這個數字本身不能定讞,畢竟「不在清單裡」只代表我們的名單沒更新。所以我做了第二次查核:從範圍外隨機抽 20 個位址去跑 FCrDNS 反解,通過數是 0 個。接著從範圍內抽 20 個當作對照組,通過數是 20 個。
對照組才是這場驗證的靈魂。如果沒有那 20 個滿分,你大可以把「範圍外 0/20」解釋成是我們的解析器壞了。但有了 20/20 的對照,殘酷的真相只剩下一個:那些人全都是假冒的。
換句話說,當一個客戶看著報表上寫著「Googlebot 造訪 N 次」,他看到的絕大部分根本不是 Google。全是一群披著外衣的騙子。
第二個例子發生在 arrivl.ai 自己家裡,所以細節我可以毫無保留地攤開來。
2026-09-01 這天,我們自家的網域湧入了 138 筆被歸類到「其他機器人」的奇怪請求:
HeadlessChrome/151
34.46.170.181,這是一個 GCP 的雲端位址。/、/integrations/* 到 /signup、/login。隔天,同一個位址對我們監測的另一個網站幹了完全一樣的事,但那一輪他更心機,把 **referer 偽造成 [https://www.google.com/](https://www.google.com/)**。
這個案例的價值在於,他不是來假冒 GPTBot 的。這是另一種更惡劣的行徑:他連裝成大廠都懶,直接套了一件無頭瀏覽器的風衣,再隨手捏造一個搜尋引擎的來路,妄想把自己裝扮成自然的過客。老實說,UA 寫著 HeadlessChrome 已經是他最誠實的瞬間了。如果他有心騙到底,換成一般 Chrome 的字串根本不需要成本,那樣他就會直接混進「人類訪客」的報表裡。
判讀這種行為的重點只有一個:行為輪廓是最便宜也最真實的訊號。 一個位址、一分鐘內、138 筆請求、路徑精準覆蓋整個註冊漏斗,光看這四點,你根本不需要去查什麼外部資料。一次真正來自 Google 搜尋的點擊絕對不會長這副德性,所以那個 referer 絕對是假的。查 IP 與 ASN 是用來確認你早就看穿的謊言,而不是用來取代你自己的雙眼。
前面三條線都有一種「查不到不代表他就是假的」的無奈極限。那有沒有那種一翻兩瞪眼、接近鐵證的判決方式?有,就是查跨廠商 UA 碰撞。
同一個 IP 位址,在同一天之內,居然自稱是兩家不同公司的伺服器端爬蟲。這就是毫無懸念的冒名劈腿。
這條規則可以踩得很死。因為兩家水火不容的競爭公司,絕對不可能共用同一台機器來發送爬蟲。GPTBot 跟 ClaudeBot 從同一個位址走出來,這在物理上就沒有任何清白的解釋。
但這裡有一個必須寫死的例外,不加上這條,你絕對會濫殺無辜:
從使用者個人裝置端發出的字串,沒有投票權。
像是連結預覽 (link preview) 抓取、手機 App 內建的 AI 客戶端,這些都是跑在使用者自己的裝置上。在同一個 NAT 出口、同一道企業防火牆背後、或是同一個電信業者的 CGNAT 池子裡,完全有可能合理地擠滿了各家廠商的字串。如果你把這些也算進劈腿判定裡,你就會把一整棟無辜的辦公大樓判成冒名現場。所以,只有那些「伺服器端主動爬取」的 UA 才有資格被拿來當作對質的證據。
這招在實務上殺傷力極強。我們在日誌鑑識時,把「跨廠商碰撞」加上「公布 IP 範圍比對」綁在一起用。在台灣某個電商網站上,自稱 AI 爬蟲的請求有極高比例被我們當場判定為冒名。這雖然只是單一網站的縮影,不能代表全球的普遍比例,但這足以證明,這組訊號真的能像照妖鏡一樣,把隱藏在 log 裡的騙子一個一個揪出來。
走到這一步,誘惑其實很大。你一定很想把這三條線索加權平均,揉成一個 0 到 100 的「可信度分數」,低於某個及格線就無腦標記成「假流量」。
千萬不要這麼做。 我們的判定表嚴格遵守三個值,而且在資料庫結構上直接鎖死,絕不給第四個曖昧的空間:
| 值 | 真實含義 | 什麼情況會落到這個下場 |
|---|---|---|
verified |
查了,而且對上了 | 位址在當天的官方清單內;FCrDNS 正反解雙雙通過檢驗。 |
unconfirmed |
查了,但沒對上 | 位址不在我們手邊的那份清單裡;PTR 存在但查出來不是他們家的。 |
unknown |
根本沒查成 | 當天清單抓取失敗;DNS 逾時;或者這隻 bot 根本沒有提供任何驗證管道。 |
有四件事你必須死死守住:
一、unconfirmed 絕對不等於「假」。 我們的資料表裡有一道 CHECK 約束,直接把 'fake' 這個字串給拒於門外。因為我知道,總有一天會有人想偷懶,把所有 unconfirmed 的人全部打成 fake。合理落進 unconfirmed 的情況至少有兩種:一種是真的從住宅區 ISP 走出來的 ChatGPT-User (因為使用者觸發的即時抓取,常常不在官方公布的爬蟲網段裡);另一種是廠商在流量已經灌進來之後,才慢吞吞補進清單的新網段。
二、抓取失敗必須歸在 unknown,不是 unconfirmed。 這條線特別容易在寫程式時搞砸,因為在邏輯上這兩者看起來都是「沒對上」,但在感情語意上卻是天壤之別。如果廠商的 JSON 伺服器回了 500 錯誤,那天所有的位址都應該是 unknown。如果你硬寫成 unconfirmed,你的報表上就會憑空長出一根巨大的「冒名尖峰」,而殘酷的真相只是你自家的抓取器當機了。DNS 也是同樣的道理,解析器逾時叫 unknown,「PTR 查得到但不是他家的」才叫 unconfirmed。
三、過期的快照只能用來證明昨天的清白。 判定必須死死綁定當天的那份快照。當今天抓取失敗時,你絕對不可以偷偷退回去拿昨天的清單來擋槍。
四、三條線必須並列,永遠不要試圖把它們融為一體。 分歧本身就是極具價值的情報。我們曾經看過 PerplexityBot 在某個時間段內的 794 次請求裡,通過 Cloudflare 驗證的次數是 0 次 (但同時流量表現一切正常)。我們也看過 Bytespider 被 Cloudflare 驗證為「搜尋引擎爬蟲」,這跟我們自己歸類的屬性完全衝突。如果你把這些線索平均成一個分數,你正好親手銷毀了這些分歧所夾帶的珍貴線索。
還有一個很容易被誤讀的 NULL 空值:「沒有驗證結果」同時代表著「驗證方看到了但他懶得驗」以及「我們根本沒去問」。這絕對不能當成 0 分來處理。實測上,流量前 30 名的專案裡,只有 7 個擁有 Cloudflare 邊緣判定的資料。如果你直接去算非空值的比例,報表就會對另外 23 個專案顯示「Cloudflare 驗證通過率 0%」。這根本是把「缺乏證據」扭曲成「證據確鑿的背叛」。
最後一條鐵律:單一的判定結果,永遠不足以觸發警報。 當你準備開口說出「你的網站有冒名問題」之前,你手邊至少要有足夠的樣本 (我們的門檻是這隻 bot 至少有 20 次被檢查過的請求) 以及足夠高的佔比。而且分母必須誠實地標示為「我們有能力檢查的請求總數」。那些打從一開始就沒有提供驗證管道的 bot,從來就不該出現在分母裡。同理,這種驗證機制應該跑在批次、離線、只讀的環境裡,絕對不該擋在收資料的門口。因為一旦判錯了方向,你就會永久刪除一筆真實的爬蟲拜訪紀錄,那是救不回來的。
unconfirmed 不是假流量,抓取失敗就是 unknown。把真實的流量隨便貼上詐騙標籤,是做分析最糟糕的墮落。明天我們要來談另一個關於「宣稱」的謊言,但方向剛好反過來。robots.txt 是我們對爬蟲做出的宣稱。當你冷酷地寫下 Disallow 之後,到底有誰會真的理你?這件事,我們教你怎麼自己量。
本文是「你的第一本 AEO x GEO 教戰手冊」系列第 4 天。系列實測與數據由 arrivl arrivl 整理 (Growth Analytics for the Agentic Web)。