用户代理精简与客户端提示迁移实践
从脆弱的用户代理解析迁移到结构化客户端提示,说明隐私、兼容性与 BotBrowser 的边界。
BotBrowser Team
User-Agent 精简是兼容性变化,不是发明新指纹的理由。网站应只读取任务所需的最小公开信号,在确有理由时请求额外提示,并保留经过测试的回退路径。
BotBrowser 可以在受授权的版本和 profile 中运行,以便在受控上下文观察这些信号;但它不能强迫网站接受 Client Hints、授予权限,也不能保证不同浏览器得到相同结果。
TL;DR
Chrome 的 User-Agent Reduction 会冻结或泛化旧 User-Agent 字符串的部分内容。UA-CH 把选定细节放入结构化请求头和 navigator.userAgentData;高熵值仍受浏览器权限和策略约束。迁移时先盘点解析器,优先能力检测,只为明确目的发送 Accept-CH,并同时测试新旧路径。BotBrowser 可为这种比较提供受控、获授权的上下文,但不能保证网站如何解释结果,也不能保证所有浏览器都得到相同结果。
内容导航
发生了什么变化
旧字符串出现在 User-Agent 请求头和 navigator.userAgent 中。精简方案有意删除或冻结细节,减少被动收集带来的可识别性。UA-CH 提供结构化的低熵提示,例如 Sec-CH-UA、Sec-CH-UA-Mobile 和 Sec-CH-UA-Platform,并由 navigator.userAgentData.brands、mobile、platform 对应表示。
platformVersion、architecture、bitness、model 和 fullVersionList 等详细值属于高熵信息。服务器可以通过 Accept-CH 请求指定值,页面也可以用 getHighEntropyValues() 请求相应 JavaScript 值。安全传输、浏览器策略、权限和用户设置都可能影响结果。
const lowEntropy = {
brands: navigator.userAgentData?.brands ?? [],
mobile: navigator.userAgentData?.mobile ?? null,
platform: navigator.userAgentData?.platform ?? 'unknown',
};
const detailed = navigator.userAgentData
? await navigator.userAgentData.getHighEntropyValues(['platformVersion', 'architecture'])
: null;
不要把缺少 API 当成某个具体设备或自动化请求的证据,它只表示这个信号不可用。
迁移步骤
- 盘点依赖。 找出服务器解析器、分析字段、CDN 规则、框架判断,以及假定
User-Agent含完整系统或次版本的测试。 - 定义产品决策。 如果问题是能力判断,使用能力检测或标准 API;如果服务器确实需要平台族,使用低熵提示并写明用途。
- 设计回退。 旧浏览器、隐私设置和非 Chromium 客户端可能不发送所请求提示。使用保守默认值,不从缺失信号推断精确设备。
- 只请求必要细节。 仅为列出的高熵字段发送
Accept-CH,复查保留周期;能用粗粒度分类时不要记录原始值。 - 测试两层。 在支持的上下文检查请求头和
navigator.userAgentData,再用合成页面测试回退。检查重定向和缓存键,因为提示可能改变服务器选择的表示。
| 决策 | 优先证据 | 安全回退 |
|---|---|---|
| 展示功能 | 运行时能力检测 | 可访问的替代控件 |
| 选择粗粒度布局 | 低熵移动提示与视口 | 响应式 CSS |
| 选择下载包 | 用户明确选择或能力 | 通用兼容包 |
| 诊断回归 | 声明的版本与测试结果 | 请求可复现步骤 |
隐私与兼容性边界
Client Hints 不是收集完整身份清单的许可。高熵请求可能增加可关联性,因此每个字段都应绑定到可见目的,缩短保留时间,并让兼容性日志排除账户、位置和无关设备数据。GREASE 品牌条目有意变化;解析器应接受未知品牌和不同顺序,而不是匹配固定列表。
把 UA-CH 当作渐进增强。代理、缓存、嵌入文档、浏览器设置或非 Chromium 实现都可能改变可见提示。navigator.userAgentData 并非处处存在,Promise 成功也不代表应用操作已完成。测试记录应分开保存浏览器观察、权限结果、应用确认和服务结果。
可参阅 自定义 User-Agent 一致性 与 浏览器功能质量,了解为什么只改一层或只看到一个 API 并不足以形成完整兼容性判断。
BotBrowser 能力边界
BotBrowser 可以提供受控配置和可重复的获授权流程,用于比较声明版本中的 User-Agent 与 UA-CH 行为。测试可以记录请求头、页面值、Worker 值、上下文假设、夹具版本和可见应用结果,并将证据限定在自有测试页面。
BotBrowser 不会让网站接受某个提示、授予权限、移除来源策略,也不会证明生产账户或交易成功。受控上下文同样不意味着可以收集完整指纹。应结合 W3C 与 MDN 语义、应用断言使用 BotBrowser 观察,并在报告中写明版本、来源、策略和回退。
容错解析与职责分离。 GREASE 品牌列表可扩展:接受未知品牌和任意顺序,忽略未来字段。API 缺失不等于 mobile: false,应保留明确的“信号不可用”状态。服务器先依据请求头做决定,页面再检测能力;若响应依赖某个提示,必须发送 Vary,同时测试冷缓存和热缓存。
合成夹具、重定向与缓存。 创建自有测试页,只显示被审查字段,并为可用、缺失、拒绝、延迟分支显示状态。测试首次导航、重定向导航和热缓存重复导航,核对 Accept-CH、缓存键及 Vary,避免一个上下文的表示被送给另一个上下文。使用合成文本,不连接账户或生产端点,并断言回退控件保留用户输入。
Worker、iframe 与可访问性。 产品使用 Worker 或 iframe 时,各加入一次检查;只修改主页面不能证明上下文一致。回退控件必须有标签、支持键盘并提供状态消息;能力缺失或拒绝后移动焦点,用户已选择回退后忽略迟到结果。
可观测性与保留。 仅保留规范化状态(hint-present、hint-denied、api-missing、fallback-used)、声明的版本、来源类别、夹具修订号和下一次复查日期。每个高熵字段都要有负责人和到期时间;不要保存完整 navigator、字体、渲染器、账户、位置或原始输入。
发布、回滚与迁移记录。 将解析器置于可逆配置后,先用合成请求比较新旧决策;提示缺失或格式错误时回到既有回退,并输出有限诊断类别而非原始请求头。记录应写明产品决策、最小信号、参考规范和 MDN、版本集合、上下文假设、回退负责人,以及请求头、页面、Worker 和应用确认的区别。在浏览器大版本、CDN 策略或嵌入集成变化后安排复查。
非 Chromium 与旧客户端。 Firefox、Safari、嵌入式 WebView、隐私工具和旧版本可能只提供精简字符串或完全没有信号。回退应是产品行为,而不是根据浏览器名称猜测:通用下载包、响应式 CSS 或明确选择通常比推断设备型号更安全。应诚实记录“提示不可用”,不要扩大为“设备不支持”。
支持沟通与包装器边界。 告诉支持人员可以请求什么观察结果,例如 Sec-CH-UA-Platform 缺失且页面显示响应式回退;不要索要完整请求头、设备清单或账户截图。框架包装器可能只修改一个页面字符串、抑制异常或延迟调用,但不会自动改变请求提示、Worker 范围或来源策略。保留一个浏览器夹具和一个用户流程,分别验证信号与应用行为。
明确不解决的问题与示例。 迁移不会识别所有浏览器、强迫服务器接受请求头、保证权限成功,也不能证明具体操作系统。使用合成平台值和粗粒度版本标签,不复制真实客户请求头;浏览器改变精简字符串或新增提示后,复查并替换示例。
责任与复查。 为服务器解析器、页面回退和隐私复查分别指定负责人,记录预期状态转换及下一次检查日期。跨边界故障应报告边界,例如“请求头缺失,已显示响应式回退”,不要笼统归咎浏览器。由工程与隐私负责人共同审阅用途、最小信号、保留负责人和再次复查条件。
实践结论
从用户决策开始,而不是从替换解析器开始。能力使用能力检测,服务器粗粒度判断使用低熵 UA-CH,只有产品确实离不开时才请求经过说明的高熵值。测试缺失、拒绝、延迟和回退状态,保留用户输入,并把浏览器证据与应用成功分开。这样可以减少脆弱假设,同时尊重隐私和浏览器上下文的证明边界。