User-Agent 是 web 上最古老的 HTTP 头之一(1993 年),但它已经不再是判断浏览器、设备、OS 的可靠依据。理解 UA 的历史包袱、各浏览器的”冻结”动作、以及替代品 Client Hints 的能力边界,能避免写出明年就失效的检测逻辑。
UA 字符串的套娃简史
今天的 UA 字符串看着像随机字符堆,实际上是 30 年的兼容历史一层层加的:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
拆开看:
| 段 | 含义 | 出现年代 | 真假 |
|---|---|---|---|
Mozilla/5.0 | ”我兼容 Mozilla” | 1998 IE 起所有浏览器都假装 | 假(套娃身份) |
(Macintosh; Intel Mac OS X 10_15_7) | OS 标识 | 1993 起 | 半真(Chrome 110 起永远写 10_15_7) |
AppleWebKit/537.36 | ”我兼容 WebKit” | 2003 Safari 起 | 假(Chrome 早就 fork 成 Blink) |
(KHTML, like Gecko) | ”我也兼容 KDE 的 KHTML 和 Mozilla 的 Gecko” | 2003 起 | 假(套娃 + 套娃) |
Chrome/120.0.0.0 | 浏览器真身 + 版本 | 2008 起 | 真(但 Chrome 110+ 次版本号永远写 0) |
Safari/537.36 | ”我兼容 Safari” | 2008 Chrome 起 | 假 |
真正有用的只有 Chrome/120 一段——其他都是兼容历史。
UA 冻结:Chrome 已经动手了
UA 字符串成为隐私和兼容性的双重负担,2020 年 Chrome 提出 User-Agent Reduction,分阶段把 UA 字段冻结到固定值:
| 阶段 | Chrome 版本 | 冻结内容 |
|---|---|---|
| Phase 1 | 92+ | 次要版本号永远 0.0.0(如 120.0.0.0) |
| Phase 2 | 100+ | 桌面 OS 版本永远固定(Mac 10_15_7、Win 10.0) |
| Phase 3 | 110+ | 移动端机型字符串简化 |
结果:
- 用 UA 判断”用户在 macOS 14 还是 12” → 不可能(永远写 10_15_7)
- 用 UA 判断”Chrome 120.0.6099.62 还是 120.0.6099.130” → 不可能(永远写 120.0.0.0)
- 用 UA 判断”用户在 iPhone 14 还是 iPhone 12” → 一直就不可能(iOS UA 不带机型)
这些信息现在要走 Client Hints。
Client Hints:UA 的现代替代品
Client Hints 是 HTTP 头家族,让浏览器按需透露详细信息:
默认就发的(低熵,所有 Chromium 浏览器都有):
Sec-CH-UA: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"
要服务端申请才发的(高熵):
Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model, Sec-CH-UA-Arch, Sec-CH-UA-Bitness
下次请求时浏览器会带:
Sec-CH-UA-Platform-Version: "14.2.1"
Sec-CH-UA-Model: ""
Sec-CH-UA-Arch: "arm"
Sec-CH-UA-Bitness: "64"
JS API:
// 默认低熵字段
navigator.userAgentData.brands; // [{brand: "Chrome", version: "120"}, ...]
navigator.userAgentData.mobile; // false
navigator.userAgentData.platform; // "macOS"
// 高熵字段(异步)
const hints = await navigator.userAgentData.getHighEntropyValues([
'platformVersion', 'model', 'architecture', 'bitness'
]);
// {platformVersion: "14.2.1", model: "", architecture: "arm", bitness: "64"}
关键限制:
- Apple 拒绝实现 Client Hints——iOS Safari、macOS Safari 都没有
userAgentData - 所以要兼容 iOS仍然只能解析传统 UA
- Firefox 实现了部分但默认关闭
实战策略:新代码先试 userAgentData,回退到 UA 解析——本工具就是这种模式。
“Sec-” 前缀和不可伪造
Client Hints 的 Sec-CH-UA* 前缀有个特性:不能被 JS 修改。
普通 HTTP 头(包括传统 UA)可以被代理 / 浏览器扩展改写。但 Sec- 前缀的头是浏览器只读——只有浏览器自己生成,扩展和 fetch 调用都改不了。
这意味着:
- 服务端如果信任
Sec-CH-UA-Platform,比信任传统 UA 更可靠 - 但爬虫工具直接构造 HTTP 请求时仍然能随意写——只是普通浏览器内不能改
- 所以反爬只防得住”浏览器端伪造”,防不住”绕过浏览器直接发请求”
Bot 识别的真实难度
UA 里带 bot 关键词的是”老实 Bot”——主动声明身份的搜索引擎和监控工具:
Googlebot/2.1 (+http://www.google.com/bot.html)
Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)
Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
识别原则:
- UA 含关键词:
bot、spider、crawler、fetch、monitor、preview - 反向 DNS 验证:
Googlebot的 IP 反查必须返回*.googlebot.com或*.google.com,再正向解析回原 IP(Forward-Confirmed Reverse DNS) - 公开声明的 IP 段:Google 发布
googlebot.json、Bing 类似
但伪装 Bot就难办了:
- 数据采集器用合法的 Chrome / Safari UA
- 通过住宅代理(如 BrightData / Oxylabs)从家庭 IP 发请求
- 用 Puppeteer / Playwright 控制真实 Chrome(绕过浏览器指纹检测)
- 模拟人类鼠标移动、滚动、停留时间
单看 UA 完全分不出。要识别得靠:
- 请求频率异常
- TLS 指纹(JA3 / JA4)
- HTTP/2 帧顺序指纹
- Canvas 指纹 + WebGL 指纹
- 鼠标轨迹机器学习
- Cookie 持久性
这些是 Cloudflare / Akamai 的核心技术——自己用 UA 写反爬等于纸糊。
AI 爬虫的新一轮
2023 年后 AI 训练爬虫成为新流量大户:
| Bot UA 关键词 | 来源 |
|---|---|
| GPTBot | OpenAI 训练数据 |
| ClaudeBot / anthropic-ai | Anthropic |
| Google-Extended | Google Bard / Gemini |
| PerplexityBot | Perplexity |
| Bytespider | 字节跳动豆包 |
| OAI-SearchBot | OpenAI 搜索 |
它们都遵守 robots.txt(理论上)。在 robots.txt 里写:
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
注意:这些 Bot 是 opt-out 模式——默认抓取你的内容用于训练,要拒绝必须主动 Disallow。
设备识别能拿到什么
普通业务想知道”用户什么设备”,能拿到的:
| 信息 | UA 能拿 | Client Hints 能拿 | 备注 |
|---|---|---|---|
| 浏览器名 + 大版本 | ✓ | ✓ | UA 仍可靠 |
| OS 名(Win/Mac/Linux/iOS/Android) | ✓ | ✓ | UA 仍可靠 |
| 桌面 OS 精确版本 | ✗(Chrome 已冻结) | ✓ | 要 platformVersion |
| iOS 精确版本 | ✓ | ✗(Apple 不支持) | UA 仍是唯一来源 |
| 设备型号(iPhone 几) | 永远拿不到 | iOS 不支持 / Android 部分 | 隐私限制 |
| CPU 架构(x64 / arm) | ✗ | ✓(Sec-CH-UA-Arch) | 仅 Chromium |
| 屏幕分辨率 | JS(screen.width) | ✗ | 客户端 JS 拿 |
| 是否触屏 | UA 含 “Mobile” | ✓ | 不可靠 |
| 暗色模式 | ✗ | ✗ | CSS @media 或 JS |
| 浏览器语言 | Accept-Language | - | 单独的 HTTP 头 |
一句话总结
UA 仍是最普及的设备识别手段但精度持续下降,要详细信息走 Client Hints(iOS 除外),反爬别只信 UA,AI 爬虫记得在 robots.txt 显式 opt-out。