指南/第 03 章

CHAPTER 03 / 12

注册与认证:把信任链串起来

WebAuthn 的浏览器调用各只有一个主要入口,但一次安全登录需要服务器、客户端、认证器和用户共同完成。理解每一步携带什么、验证什么,才能判断代码是否真正实现了认证。

英文原文 §1.2 用例 · §1.3 API 示例 · §7 RP 操作

原文重点:你链接的登录场景#

你提供的锚点是 §1.2.2 Authentication。下面是该2021 年用例的中文译解,用来理解电脑与手机协作的角色,不应照搬为现代用户操作说明:

  1. 用户在电脑上通过蓝牙与手机配对,打开 example.com 并发起登录;浏览器提示到手机完成操作。
  2. 手机显示登录该网站的通知;用户打开通知,从账户列表中选择身份,再通过已配置的 PIN、生物识别等方式授权。
  3. 电脑上的网站显示所选账户已登录,并进入登录后的页面。

**现代补充:**今天的跨设备通行密钥体验可能由浏览器显示二维码并通过 hybrid 等机制协调。开发者应交给系统界面引导,不应要求所有用户先手工完成传统蓝牙配对。设备、浏览器和凭据提供者能力不同,也可能直接使用已同步到当前设备的通行密钥。Level 3 消费者多设备用例

这段用例说明了一个重要事实:执行网页的设备与使用私钥的设备可以不同。对 RP 服务器来说,最终仍然要验证同一套带上下文的响应,不能因为界面看起来像“手机确认”就降低验证要求。

注册:从已有账户到一个新公钥#

text
用户           RP 服务器              浏览器 / 系统             认证器
 |  已确认账户     |                       |                       |
 |--------------->|                       |                       |
 |                | 生成并保存 challenge  |                       |
 |                |----注册选项---------->|                       |
 |                |                       | create({ publicKey }) |
 |                |                       |----请求创建---------->|
 |<--------------------------显示账户 / 请求本地授权---------------|
 |---------------------------同意并完成 UV----------------------->|
 |                |                       |<---凭据与证明数据------|
 |                |<---注册响应 JSON-------|                       |
 |                | 验证并保存公钥 / ID    |                       |
 |<----添加成功----|                       |                       |

注册选项包括 RP 标识、用户句柄、随机挑战、支持的算法和认证器选择要求。浏览器会检查安全上下文和 RP ID 关系,组织客户端数据;认证器创建凭据并返回认证器数据及相关证明材料。

服务器收到响应后不能直接保存客户端随便提交的“公钥字符串”。它要依据§7.1 注册算法验证客户端数据、认证器数据、证明及本地策略,然后将验证得到的凭据公钥绑定到服务器早已确定的账户。

对不请求设备证明的普通应用,attestation: "none" 允许避免复杂证明信任链;这不会免除来源、挑战、RP ID 或 UV 检查。注册是否具有特定硬件来源保证,与“新公钥已安全绑定到哪个账户”是相关但不同的判断。

认证:用已保存公钥验证新挑战#

text
用户           RP 服务器              浏览器 / 系统             认证器
 |  点击登录       |                       |                       |
 |--------------->|                       |                       |
 |                | 生成新的 challenge    |                       |
 |                |----认证选项---------->|                       |
 |                |                       | get({ publicKey })    |
 |                |                       |----请求断言---------->|
 |<--------------------------选择账户 / 完成本地验证---------------|
 |                |                       |<---签名及上下文--------|
 |                |<---认证响应 JSON-------|                       |
 |                | 查公钥并完成全部验证   |                       |
 |                | 消费 challenge / 建会话|                       |
 |<----登录成功----|                       |                       |

服务器可以先让用户输入用户名,再下发该账户的 allowCredentials;也可以省略列表,依靠可发现凭据让用户在系统界面选择账户。二者的差别是凭据发现和账户定位方式,不改变签名与上下文校验的必要性。英文原文 §7.2 认证算法

签名到底覆盖什么#

认证时,签名的核心输入为:

text
authenticatorData || SHA-256(clientDataJSON)

|| 表示字节拼接。clientDataJSON 是浏览器提供的原始 UTF-8 JSON 字节,其中包含操作类型、challenge、origin 等。authenticatorData 包含 RP ID 的哈希、UP/UV 标志、签名计数器,以及可能存在的扩展数据。英文原文 §6.1 Authenticator Data · §5.8.1 客户端数据

服务端必须对收到的原始 clientDataJSON 字节做哈希。先解析为对象、再 JSON.stringify() 会改变空白、属性顺序等,可能得到不同字节。解析用于检查字段,原始字节用于签名输入,两项工作都需要。

公钥验证通过,只能说明签名与该输入相符;如果服务器没检查其中的挑战或 origin,攻击者仍可能把不属于当前操作的有效签名提交过来。因此,“调用验签函数返回 true”不等于“完整认证通过”。

密码登录与 WebAuthn 的差别#

维度 常见密码登录 WebAuthn 登录
用户侧认证材料 需记忆或由密码管理器填写的共享秘密 由认证器管理的凭据私钥
服务器主要保存 加盐密码哈希及参数 凭据 ID、公钥、账户绑定与状态
每次请求的核心证明 用户提交密码,服务器检查 对新挑战与上下文的签名
假站风险 用户可能把密码交给假站 标准客户端限制凭据的 RP 作用域
账户恢复 常见邮件 / 短信 / 人工流程 仍需设计;可结合备用凭据与恢复机制
服务器验证难点 密码哈希、限速、泄露防护 挑战生命周期、来源 / RP 绑定、签名及标志验证

公钥被读取不等于私钥泄露,因此服务器凭据库泄露的后果与密码哈希库不同;但账户信息、凭据 ID 和元数据仍有隐私与攻击价值,不能因此放弃访问控制或审计。

首次开户、添加凭据、重新认证#

这三个业务流程都可能调用 create() 或 get(),但授权条件不同:

  • **首次开户:**先确定产品如何分配账户和验证联系方式;WebAuthn 不会自动证明用户拥有某个邮箱。
  • **添加凭据:**必须基于可信账户上下文,例如已有登录会话,并视风险要求近期重新认证;防止被盗会话轻易增加攻击者凭据。
  • **敏感操作重新认证:**使用新的 challenge,明确绑定当前账户和操作;成功后授予有限时间或一次性的操作权限。

原文的§1.2.3 新设备注册用例展示了先用已有安全密钥登录,再添加新设备平台认证器的思路。它也说明一个账户允许多凭据,对设备更换和恢复很有价值。

浏览器响应与服务器响应要分开#

浏览器弹出成功动画,仅表示本地凭据操作完成;服务器可能因 challenge 过期、origin 不符或账户绑定错误而拒绝。前端应等待验证接口确认后再显示“登录成功”。

同样,NotAllowedError 可能涵盖用户取消、超时或无合适凭据等多种情况。页面应提供“未完成本次操作,可重试或选择其他方式”的正常反馈,而不是断言用户没有通行密钥或密码错误。

学习检查#

尝试分别说出注册和认证时服务器“发什么、记什么、验什么、存什么”。如果回答里缺少服务器保存的预期 challenge,或者只提到公钥验签,那么信任链还没有闭合。接下来的两章将把请求与返回字段逐一对应到这条链上。

读懂原理之后,用示例验证你的理解。

搜索指南

输入关键词,查找你想了解的内容。

搜索覆盖全部 12 章 · 点击结果定位到相关段落
学习目录