网站决定是否提供通行密钥登录前要做两项零权限的 WebAuthn 检测,结果也会暴露设备类型、系统版本下限和浏览器引擎——一个微弱却说明问题的指纹信号。
2026 年 8 月,谷歌的 Android Developers 官方博客介绍了 WhatsApp 如何为 10 亿用户升级到通行密钥登录——这说明通行密钥(passkey)已经从尝鲜功能变成了主流默认选项。WhatsApp 是原生 Android 应用,但同样的转变也正在网页上发生:登录页面在提供通行密钥选项之前,得先问浏览器一句"这台设备能用通行密钥吗?"。本文要讲的,就是这个问题的答案会暴露什么——既暴露给发起询问的网站,也暴露给同一页面上运行的其他任何脚本。
核心要点
- 决定是否显示通行密钥界面的两项能力检测,都不需要任何权限。
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()和isConditionalMediationAvailable()都返回 Promise,没有权限弹窗、不需要用户手势,也不显示任何界面——参见 WebAuthn Level 3 规范 与 MDN 参考文档。 - 返回的真/假值与设备类型、系统版本下限和浏览器引擎相关。 平台认证器指的是设备内置的用户验证能力——Face ID、Touch ID、Windows Hello 或 Android 锁屏——它与特定的系统版本和引擎绑定,因此一个布尔值对访客的区分程度,比你想象的要明显。
- 老实说,它的信息熵很低。 即便加上较新的
getClientCapabilities()返回的整组能力值,这些答案也大多与 User-Agent 已透露的信息重叠,单独使用几乎无法缩小身份范围。 - 它真正的价值在于矛盾检测,而不是身份标识。 值得关注的情形是:User-Agent 自称是最新旗舰手机,平台认证器却不可用——这正是反检测浏览器或模拟器的典型特征。
- 这项检测只暴露能力。 它无法让脚本知道你在这个网站或任何网站上有没有通行密钥,更无法知道你是谁——那需要一次明确的、经用户验证的、限定于单一依赖方的凭据流程。
每个"使用通行密钥?"按钮背后的两项检测
登录页面想提供通行密钥选项,首先得弄清设备能不能生成通行密钥。WebAuthn 为此在 PublicKeyCredential 上提供了两个静态方法,均定义于 W3C 维护的 WebAuthn Level 3 规范:
isUserVerifyingPlatformAuthenticatorAvailable()只回答一个问题:这个浏览器在这台设备上,能否调用一个可验证用户身份的内置认证器——Face ID 或 Touch ID、Windows Hello(人脸、指纹或 PIN),或者 Android 设备的生物识别或锁屏验证?MDN 文档将它描述为返回Promise<boolean>的静态方法。isConditionalMediationAvailable()回答一个范围更窄、但相关的问题:浏览器能否在普通用户名输入框里,以自动填充建议的形式(即"条件式界面")提供通行密钥,而不必弹出模态对话框打断页面?
较新的浏览器还增加了第三个、覆盖面更广的方法:PublicKeyCredential.getClientCapabilities(),一次调用就返回一整组布尔值——条件式获取与创建、混合(跨设备)传输、通行密钥平台认证器支持、相关源请求(Related Origin Requests)、较新的 "signal" 系列方法,以及所支持的扩展。和前两项检测一样,它只要求安全(HTTPS)上下文。
这些方法都具备与本文相关的三个共同点:无需权限弹窗、无需用户手势、自身不产生任何可见界面。页面一加载就能调用,几毫秒内拿到结果,访客全程毫无察觉。这是有意为之——登录页面本就应该悄悄判断"使用通行密钥登录"这个选项值不值得显示。但正因为悄无声息,页面上运行的任何脚本都能读到这个答案,而不只是真正需要它的登录代码。
一对真/假值究竟与什么相关
单个布尔值听起来几乎不含信息——只有一个比特。但这个比特并非独立的随机噪声,它由真实的软硬件条件决定,对访客的区分度远超"一个比特"给人的印象:
- 设备类型。 平台认证器通常依托硬件级密钥存储——安全隔区(secure enclave)、TPM 或 Android 硬件密钥库。较老的台式机、许多虚拟机以及部分 Linux 环境无法提供;在手机上,结果还取决于用户是否真的设置了锁屏。
- 系统版本下限。 每个操作系统都是从某个特定版本开始支持平台认证器的;返回
true意味着设备版本不低于这个下限,这比大多数被动信号能给出的精度都高。 - 浏览器引擎。 各引擎接入这个 API 的时间和方式并不一致,所以结果也能间接圈定当前使用的渲染引擎,以及大致的版本范围。
- 在某些配置下,还能透露设备是否受管控或处于虚拟化环境。 没有硬件级安全存储的设备——某些虚拟机、某些锁定的企业托管镜像——即使上报的操作系统和浏览器本应支持,也可能返回
false。
综合起来,一对布尔值的作用就不再像两个比特,而更像一个针对设备世代、系统版本下限和引擎的粗粒度分类器——这些信号背后的原理,可参阅我们的浏览器指纹识别指南。但它终究只是分类器,而不是查询表。这种相关性真实且有用,但不能当作关于某台具体设备的确凿证据。
熵值实话实说:几个比特,不是身份标识
这件事很容易被夸大,但不该夸大。单独来看,isUserVerifyingPlatformAuthenticatorAvailable() 只返回一个比特,isConditionalMediationAvailable() 最多再加一个。getClientCapabilities() 返回的字段更多,但它们并不相互独立:大部分字段会随浏览器品牌和版本一起变化,因为各厂商都是成批上线这些功能的。对想把它当作独立身份标识的人来说更不妙的是,这些信息几乎都与 User-Agent 字符串已经透露的操作系统和浏览器版本相关。把它加进现有指纹,几乎缩小不了原本没缩小的范围。
它的用武之地在别处:用作矛盾检测,而不是身份标识。检测方并不孤立地关心"返回了什么值",而是看这个值与页面已掌握的其他信息是否一致。User-Agent 自称是当前旗舰手机,isUserVerifyingPlatformAuthenticatorAvailable() 却返回 false,这就是值得标记的矛盾:真正的旗舰手机都内置平台认证器,而且几乎都设置了锁屏。同样,User-Agent 自称是较新版本的 Chrome 或 Safari,却完全没有 getClientCapabilities() 方法,也说不通。这种矛盾正是反检测浏览器配置和伪装的自动化程序的常见破绽:一个声称的属性(很新的 UA 字符串)与另一个属性(没有平台认证器、没有 TPM、没有安全隔区)对不上,因为这套配置是拼凑出来的,而不是从真实设备上测得的。
媒体设备指纹识别等其他零权限硬件探测,也是同样的思路:没有哪一项检测能单独认出你,但每多一项,伪造的配置就多一处必须自圆其说的地方——而保持前后一致,远比伪造任何单个数值更难。
讽刺之处:为隐私而生,自己却成了一个小信号
这一点值得细想。通行密钥的设计初衷,是用"仅限单个网站、无法跨站关联"的密钥对,取代容易被钓鱼、又常被多个网站重复使用的密码。可恰恰是提供这项改进的 API,仅仅因为存在并回答 true 或 false,就泄露了一个微小的被动信号。
有两点补充能让这个结论保持客观,而不是危言耸听。第一,软件认证器和虚拟认证器是为测试而存在的——浏览器开发者工具和 CI 环境可以注册虚拟平台认证器,在完全没有生物识别硬件的机器上也返回 true,所以这项检测并非在所有场景下都能证明硬件存在。第二,这项检测无法区分"根本没有认证器"和"有但没设置"。一部有指纹传感器但没设锁屏的手机,或一台从未注册 Windows Hello 的电脑,在这个 API 看来,可能与从来没有这类硬件的设备毫无二致。两点指向同一个结论:应把它当作微弱的辅助信号,而非强信号——矛盾检测的价值在于运行成本低,而不在于单凭它就能下结论。
这项检测暴露不了什么
这一节需要说得格外准确,因为一旦夸大其词,最伤读者信任的就是这里:
- 它无法暴露你在这个网站或任何网站上是否有通行密钥。 "能力"(这台设备能不能用通行密钥)和"注册"(某个依赖方下是否已有具体凭据)是两个完全不同的问题,这个 API 只回答前者。
- 它无法暴露你的身份。 WebAuthn 凭据在设计上只限定于单一依赖方——为某个网站创建的通行密钥,其他网站无法读取、枚举或关联;每个网站拿到的都是自己独立的密钥对,而不是像第三方 Cookie 那样的共享标识符。
- 要真正使用凭据,必须经过一次明确的用户验证。 能力检测是静默的,但真正用通行密钥登录,仍需用户完成生物识别或 PIN 验证。能力检测本身并不会让任何人离这一步更近。
这种作用域限定是刻意的设计选择,提供的隐私边界也比大多数被动指纹信号更强。可以拿它与设备认证对比:设备认证针对某台具体设备,给出的是经过密码学签名、强得多的断言,而不是一个软性的、低熵的能力比特。在这条谱系上,通行密钥能力检测与匿名凭据更为接近——两者都旨在证明某个有限的属性而不暴露身份;设备认证则是本质上更强、也更具识别性的断言。如果你关心的是网站如何推断你登录了哪些账号,而不是你的硬件能做什么,那是另一套完全不同的机制——参见跨站登录检测。
结论
通行密钥能力检测,是本博客反复讨论的"一致性检查"思路的一个典型例子:单独都很弱的信号,相互交叉验证后,能发现的问题比任何单一强信号都多。它本身算不上指纹,也不像追踪 Cookie 或认证令牌那样构成隐私风险——但它又是一个检验"你声称自己是什么"与"你的设备实际能做什么"是否吻合的地方。
我们的工具目前并不检测通行密钥支持情况,但能展示通行密钥检测结果会被拿来交叉比对的那些信号:运行指纹检测,查看你的浏览器暴露了哪些 User-Agent、平台和硬件属性;或者试试机器人检测,看看这些属性之间的矛盾是如何被标记出来的。
常见问题
检测通行密钥支持需要我的授权吗?
不需要。isUserVerifyingPlatformAuthenticatorAvailable()、isConditionalMediationAvailable() 和 getClientCapabilities() 都是静默的、基于 Promise 的检测——没有权限弹窗,不需要用户手势,页面上也看不到任何变化。
网站能知道我是否保存了通行密钥吗?
不能。这些检测报告的是设备能力——是否存在平台认证器——而不是你在某个网站或任何网站上是否注册了通行密钥。凭据注册情况按依赖方隔离,这个 API 不会暴露。
这项检测返回 false 一定有意义吗?
单看它本身,不一定。它可能表示设备确实没有平台认证器,也可能是有但没设置(例如没设锁屏或没注册 Windows Hello),或者在测试环境中只是还没注册虚拟认证器。应把它当作一个微弱的辅助信号,而不是确定的答案。
这和设备认证有什么区别?
强度上差别很大。能力检测只是一个软性的、低熵的布尔值,与设备类型和操作系统/浏览器版本相关。设备认证则是针对某台具体设备、经密码学签名、由硬件支撑的声明——强得多,也更具识别性。
推荐阅读:


