无密码登录的底层工作原理
你点击”登录”,手机要求指纹验证,然后你就通过了身份认证。无需输入密码,无需从邮件中复制验证码。如果你之前实现过身份认证流程,这可能让你感觉像魔法一样——或者更糟,像一个你需要集成却无法理解的黑盒。
本文将解释 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 设计为跨平台兼容。存储在平台密钥链(如 iCloud 钥匙串或 Google 密码管理器)中的同步型 passkeys 可在该生态系统内的设备间工作。对于跨生态系统认证,用户可以扫描二维码使用存储在不同设备上的 passkey 进行认证,利用 FIDO2 混合传输协议。
每个 passkey 凭证都是唯一的,并绑定到特定的用户账户和依赖方。当同一域名存在多个 passkeys 时,浏览器或认证器会呈现选择界面,让用户选择使用哪个凭证。服务器端存储的凭证 ID 将每个 passkey 映射到其对应的用户账户。
Passkeys 通过源绑定抵御中间人攻击。认证器在签名的认证响应中包含确切的源。如果攻击者拦截并通过代理中继认证尝试,源不匹配会导致签名验证失败。密码学绑定使实时钓鱼攻击无效。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.