User-Agent 不再可靠:UA 冻结、Client Hints 与设备识别的边界

· 约 5 分钟 🕵️ User-Agent 解析

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 192+次要版本号永远 0.0.0(如 120.0.0.0
Phase 2100+桌面 OS 版本永远固定(Mac 10_15_7、Win 10.0)
Phase 3110+移动端机型字符串简化

结果

  • 用 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)

识别原则

  1. UA 含关键词:botspidercrawlerfetchmonitorpreview
  2. 反向 DNS 验证:Googlebot 的 IP 反查必须返回 *.googlebot.com*.google.com,再正向解析回原 IP(Forward-Confirmed Reverse DNS)
  3. 公开声明的 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 关键词来源
GPTBotOpenAI 训练数据
ClaudeBot / anthropic-aiAnthropic
Google-ExtendedGoogle Bard / Gemini
PerplexityBotPerplexity
Bytespider字节跳动豆包
OAI-SearchBotOpenAI 搜索

它们都遵守 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。

❓ 常见问题

为什么 Chrome 的 User-Agent 还写着 "Mozilla/5.0" 和 "Safari"?

历史包袱。1993 年 Mosaic 开始用 Mozilla,Netscape 继承(Mozilla 是 Mosaic Killer 的简称);1998 年 IE 假装是 Netscape 才能拿到为 Netscape 写的"高级"页面,所以 IE UA 也写 Mozilla;2003 年 Safari 假装是 Mozilla 兼容2008 年 Chrome 假装是 Safari 兼容——一层层套娃。今天 Chrome 的 UA 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 / Mac / WebKit / KHTML / Gecko / Chrome / Safari 七种身份——真正有用的只有 "Chrome/120"。

听说 Chrome 在"冻结 UA"是怎么回事?

2020 年 Chrome 84 起开始 UA Reduction。理由:UA 暴露太多信息(精确版本、设备、OS),成为浏览器指纹的主要来源;同时 UA 越长越不可信(站点写一堆 if-else 给不同浏览器特殊处理,造成 web 兼容性恶性循环)。结果:Chrome 110+ 的 UA 不再带次版本号、Mac 版本号永远写 "10_15_7"、Windows 版本号永远写 "10.0"——开发者要详细信息要走 Client Hints(HTTP 头 / JS API)显式申请。Edge / Brave 跟进。Firefox 也在冻结但策略不同。

怎么用 Client Hints 拿真实信息?

两种方式。HTTP 头:服务端响应里加 Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model,下次请求浏览器会带 Sec-CH-UA-Platform-Version: "14.2.1"JS APInavigator.userAgentData.getHighEntropyValues(['platformVersion', 'model']) 返回 Promise。默认就有的低熵字段Sec-CH-UA(品牌+大版本,"Chrome";v="120")、Sec-CH-UA-MobileSec-CH-UA-Platform注意:iOS Safari 不支持 userAgentData——Apple 拒绝跟进 Client Hints,要兼容 iOS 仍然只能解析传统 UA。

反爬虫识别 Bot 真的能识别准吗?

看 Bot 类型。老实 Bot(Googlebot / Baiduspider / 各种站长工具)会在 UA 里带 bot/spider/crawler 关键词 + 联系方式 URL,反向 DNS 也能验证(Googlebot 的 IP 反查到 *.googlebot.com)——识别接近 100%。伪装 Bot(数据采集、价格爬虫)会用合法浏览器 UA + 真实 IP(住宅代理),单看 UA 完全分不出,要靠请求频率 / Canvas 指纹 / WebGL 指纹 / 鼠标轨迹综合判断。反爬现状:UA 只是第一层过滤,专业爬虫早就绕过;想真挡得上 Cloudflare / Akamai 这种综合方案。

🕵️ 打开 User-Agent 解析 浏览器/OS/设备/引擎一键拆解·常见 UA 示例·Bot 识别·本地解析