你点击”登录”,手机要求指纹验证,然后你就通过了身份认证。无需输入密码,无需从邮件中复制验证码。如果你之前实现过身份认证流程,这可能让你感觉像魔法一样——或者更糟,像一个你需要集成却无法理解的黑盒。
本文将解释 passkeys(通行密钥)和 WebAuthn 在浏览器 API 底层的实际工作原理。你将理解身份认证流程、涉及的密码学原语,以及使基于 FIDO2 的无密码认证从根本上区别于魔法链接或 OTP 等旧方法的安全特性。
核心要点
- Passkeys 使用公钥加密技术,私钥永远不会离开你的设备,消除了攻击者可以拦截或窃取的共享密钥。
- WebAuthn 认证涉及四方:你的前端、浏览器 API、认证器(设备密钥链或硬件密钥)以及你的服务器。
- 源绑定提供了密码学级别的抗钓鱼能力——凭证绑定到特定域名,在仿冒网站上无法工作。
- 条件式 UI 允许 passkey 提示出现在自动填充建议中,创造无缝的认证体验。
为什么 Passkeys 取代了早期的”无密码”方法
魔法链接和一次性密码从登录表单中移除了密码字段,但它们并没有消除共享密钥。魔法链接仍然是通过电子邮件传输的持有者令牌——可被拦截、可重放,并且如果用户在伪造域名上点击链接就会被钓鱼。通过短信发送的 OTP 容易受到 SIM 卡交换攻击。
Passkeys 以不同的方式解决了这个问题。它们使用公钥加密技术,其中密钥(你的私钥)永远不会离开你的设备,也永远不会通过网络传输。服务器只存储你的公钥,即使数据库被破解,公钥对攻击者也毫无用处。
这是 FIDO2 和 WebAuthn 背后的核心理念:认证通过密码学证明持有权来实现,而不是传输密钥。
WebAuthn 认证流程
当用户使用 passkey 进行认证时,通常有四个组件交互:你的前端代码、浏览器的 WebAuthn API、认证器(通常是操作系统密钥链、手机或硬件安全密钥)以及你的服务器。
注册:创建凭证
在注册期间,你的服务器生成一个挑战(challenge)——一个随机字节序列——并将其与你的依赖方 ID(通常是你的域名)一起发送到浏览器。你的前端使用这些参数调用 navigator.credentials.create()。
浏览器通过 CTAP(客户端到认证器协议)将此请求传递给认证器。认证器生成一个新的密钥对,安全地存储私钥,并返回公钥以及签名的证明(attestation)。
你的服务器接收并存储公钥、凭证 ID 以及签名计数器等元数据。没有密码哈希,没有共享密钥——只有一个限定在你域名范围内的公钥。
认证:证明持有权
当用户返回时,你的服务器生成一个新的挑战。你的前端调用 navigator.credentials.get(),浏览器提示认证器。
认证器找到与你的 RP ID 匹配的凭证,要求用户验证(生物识别、PIN 或存在性验证),然后使用私钥对挑战进行签名。此签名连同认证器数据一起返回到你的服务器。
你的服务器根据存储的公钥验证签名。如果匹配,用户就证明了他们持有私钥,而无需传输它。
源绑定:抗钓鱼机制
这就是使 passkeys 真正具有抗钓鱼能力而不仅仅是”更难钓鱼”的原因。认证器将凭证密码学地绑定到依赖方的源。
在对挑战进行签名时,认证器在签名数据中包含依赖方 ID 哈希(从你的域名派生)。如果攻击者在 g00gle.com 创建一个仿冒网站,google.com 的凭证根本无法工作——源不匹配,认证器不会生成有效的签名。
这不是用户可以点击跳过的 UI 警告。它在协议层面通过密码学强制执行。
Discover how at OpenReplay.com.
同步型与设备绑定型 Passkeys
现代 passkeys 通常通过操作系统密钥链在设备间同步——Apple 的 iCloud 钥匙串、Google 密码管理器或 1Password 等第三方管理器。这极大地提高了可用性,因为用户在更换手机时不会失去访问权限。
设备绑定型 passkeys(如硬件安全密钥)提供更强的保证——私钥可证明地仅存在于一个设备上。对于大多数 Web 应用程序,同步型 passkeys 在提供更好用户体验的同时也能提供足够的安全性。你的威胁模型决定了哪个更重要。
现代用户体验模式:条件式 UI
你可能见过 passkey 提示出现在用户名字段的自动填充建议中。这就是条件式 UI——浏览器在用户明确请求无密码登录之前主动提供可用的 passkeys。
通过调用带有 mediation: 'conditional' 参数的 navigator.credentials.get() 并在输入字段中添加 autocomplete="username" 来实现此功能。
浏览器处理发现和呈现。
许多应用程序现在使用条件式 UI 来升级现有用户:在成功的密码登录后,提示用户注册 passkey 以供将来会话使用。
安全属性和信任边界
Passkeys 大幅减少了攻击面,但它们不是魔法。私钥的安全性取决于认证器的实现——通常是设备的安全区域或 TPM。如果设备本身在硬件层面被攻破,一切安全保证都将失效。
账户恢复仍然是一个设计挑战。当用户丢失所有设备时,你需要备用机制,但不能重新引入 passkeys 消除的漏洞。
WebAuthn 持续演进——Level 3 是当前一代规范——正在进行跨设备认证和企业证明方面的工作。这里介绍的基础知识保持稳定。
结论
Passkeys 将认证从”验证用户知道某个密钥”转变为”验证用户持有某个密钥”。这改变了你的思维模型:你不是在检查密码与哈希的匹配,而是在验证密码学签名与公钥的匹配。
对于前端工程师来说,实际意义很直接:学习 WebAuthn API 的注册和认证流程,实现条件式 UI 以实现无缝发现,并设计升级路径,让用户从密码逐步迁移到 passkeys。
常见问题
如果用户丢失了所有带有同步 passkeys 的设备会怎样?
当用户丢失所有设备时,账户恢复变得至关重要。常见方法包括注册期间生成的备份恢复代码、已验证邮箱等辅助认证方法,或身份验证流程。挑战在于设计不会重新引入 passkeys 消除的漏洞的备用方案,例如可钓鱼的魔法链接或可拦截的短信验证码。
Passkeys 可以跨不同浏览器和操作系统工作吗?
可以,passkeys 设计为跨平台兼容。存储在平台密钥链(如 iCloud 钥匙串或 Google 密码管理器)中的同步型 passkeys 可在该生态系统内的设备间工作。对于跨生态系统认证,用户可以扫描二维码使用存储在不同设备上的 passkey 进行认证,利用 FIDO2 混合传输协议。
Passkeys 如何处理同一网站上的多个账户?
每个 passkey 凭证都是唯一的,并绑定到特定的用户账户和依赖方。当同一域名存在多个 passkeys 时,浏览器或认证器会呈现选择界面,让用户选择使用哪个凭证。服务器端存储的凭证 ID 将每个 passkey 映射到其对应的用户账户。
Passkeys 容易受到中间人攻击吗?
Passkeys 通过源绑定抵御中间人攻击。认证器在签名的认证响应中包含确切的源。如果攻击者拦截并通过代理中继认证尝试,源不匹配会导致签名验证失败。密码学绑定使实时钓鱼攻击无效。