📋 目录
概述
什么是 Passkey?
Passkey 是基于 FIDO2/WebAuthn 标准的无密码认证技术,使用公钥加密和生物识别(指纹、人脸、PIN)来替代传统密码。
核心优势
- ✅ 无密码:无需记忆复杂密码
- ✅ 更安全:私钥永不离开设备,无法被窃取
- ✅ 便捷:支持无用户名登录(可发现凭证)
- ✅ 跨平台:支持电脑、手机、USB 密钥等多种设备
技术栈
- 前端: Next.js 14 (App Router), React, Ant Design
- 后端: Next.js API Routes
- Passkey 库:
@simplewebauthn/server,@simplewebauthn/browser - 存储: 文件存储(生产环境应使用数据库)
FIDO2 与 WebAuthn 标准
FIDO2 组成
FIDO2 由两个核心规范组成:
-
WebAuthn (Web Authentication API) - W3C 标准
- 浏览器端的 JavaScript API
- 定义如何与认证器交互
- 由浏览器厂商实现
-
CTAP2 (Client to Authenticator Protocol 2) - FIDO Alliance 标准
- 定义客户端与认证器之间的通信协议
- 支持 USB、NFC、BLE 等传输方式
- 由认证器厂商实现
架构图
┌─────────────┐
│ Web 应用 │
└──────┬──────┘
│ WebAuthn API
│ (navigator.credentials)
▼
┌─────────────┐
│ 浏览器 │
└──────┬──────┘
│ CTAP2 协议
│ (USB/NFC/BLE)
▼
┌─────────────┐
│ 认证器 │
│ (Passkey) │
└─────────────┘
标准符合性
当前实现完全符合 FIDO2 标准:
- ✅ 使用标准 WebAuthn API
- ✅ 使用标准服务端验证库
- ✅ 实现可发现凭证(FIDO2 Level 2)
- ✅ 符合所有安全要求
- ✅ 支持多种算法和传输方式
安全机制
1. 防重放攻击
- Challenge:每次请求生成新的随机 challenge
- Counter:每次使用后递增,防止重复使用
- 时效性:Challenge 通常有时效性(如 60 秒)
2. 域名验证
- Origin:验证请求来源
- RP ID:验证依赖方ID(域名)
3. 用户验证
- User Verification:要求用户验证(指纹/人脸/PIN)
- 防止:设备被盗用
4. 签名验证
- 私钥:永远不离开设备
- 公钥:存储在服务端,用于验证签名
5. 防克隆攻击
- 计数器:每次认证后,签名计数器递增
- 验证:服务器检查计数器是否递增
- 检测:如果计数器 ≤ 已保存的值 → 可能是克隆凭证
安全模型
注册时:
认证器生成密钥对(私钥 + 公钥)
私钥 → 永远留在设备本地(永不传输)
公钥 → 发送给服务器保存
登录时:
服务器发送 challenge
认证器用私钥签名 challenge
服务器用公钥验证签名
关键概念
1. Challenge(挑战)
- 作用:防重放攻击
- 生成:服务端生成随机字符串
- 验证:确保响应是针对当前请求的
2. User ID(用户标识)
- 注册时:服务端生成唯一ID,传入
user.id - 存储位置:认证器设备本地(可发现凭证)
- 登录时:从
userHandle中获取
3. Resident Key(可发现凭证)
- 特点:用户信息存储在设备本地
- 优势:登录时无需输入用户名
- 设置:
requireResidentKey: true
4. AllowCredentials(允许的凭证)
- 提供时:限制只能使用指定的凭证
- 不提供时:浏览器枚举所有可发现凭证(无用户名登录)
5. Counter(计数器)
- 作用:防止重放攻击
- 规则:每次使用后必须递增
- 验证:服务端检查 counter 是否大于上次的值
6. Signature(签名)
- 生成:使用私钥对
challenge + authenticatorData签名 - 验证:使用公钥验证签名,证明拥有私钥
参考资料
总结
本文档提供了 Passkey 功能的完整指南,包括:
- ✅ 概述和标准:FIDO2/WebAuthn 标准说明
- ✅ 关键概念:关键概念
- ✅ 安全机制:各种安全措施和最佳实践
当前实现完全符合 FIDO2 标准,支持可发现凭证(无用户名登录),是一个完整的 Passkey 认证系统!