关于 implementing-hardware-security-key-authentication
面向开发者的实践指南,介绍如何用 WebAuthn 实现 FIDO2 硬件密钥和 Passkey 身份验证,涵盖注册、验证、迁移与恢复。
主要功能
- 01配置 WebAuthn 信赖方
- 02注册并验证凭据
- 03管理 YubiKey 生命周期
- 04规划 Passkey 迁移与恢复
适用场景
- 01为 Web 服务添加抗钓鱼 MFA
- 02支持免用户名 Passkey 登录
- 03登记主用及备用安全密钥
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill implementing-hardware-security-key-authentication安装后在 Claude Code 中输入/implementing-hardware-security-key-authentication确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdscripts/agent.py详细介绍
实现硬件安全密钥认证
适用场景
- 为高价值账户(管理员、开发者、特权用户)使用 FIDO2 硬件安全密钥部署抗钓鱼的多因素认证(MFA)
- 构建同时支持漫游认证器(USB/NFC 安全密钥)和平台认证器(Windows Hello、Touch ID、Android 生物识别)的 WebAuthn 依赖方服务器
- 将现有基于密码的认证系统迁移为支持通行密钥(可发现凭据)作为主认证因素或辅助认证因素
- 为组织员工注册 YubiKey 设备,包括 PIN 设置、凭据注册和备用密钥配置
- 实现符合 NIST SP 800-63B AAL3(认证器保证等级 3)要求的无密码认证流程
请勿在生产环境中不使用 HTTPS 的情况下使用(WebAuthn 要求安全来源),也不适用于用户无法物理接触 USB/NFC 端口的系统,或在没有丢失密钥恢复机制的情况下将其作为唯一的认证因素。
前置条件
- Python 3.10+,并已安装
fido2(python-fido2 >= 2.0.0)、flask和cryptography库 - 启用 HTTPS 的 Web 服务器(WebAuthn API 要求安全上下文;开发环境下 localhost 可豁免)
- 兼容 FIDO2 的硬件安全密钥(YubiKey 5 系列、SoloKeys、Titan Security Key)或平台认证器
- 支持 WebAuthn API 的现代 Web 浏览器(Chrome 67+、Firefox 60+、Safari 14+、Edge 79+)
- 了解公钥密码学、挑战-响应协议和 HTTP 会话管理
工作流
步骤 1:依赖方服务器配置
配置 WebAuthn 依赖方(RP)身份和服务器:
- 定义 RP 身份:创建
PublicKeyCredentialRpEntity,包含依赖方名称(向用户显示的显示名称)和 RP ID(应用程序的有效域)。RP ID 必须是来源的可注册域后缀——例如,example.com对https://auth.example.com有效,但other.com无效。 - 初始化 Fido2Server:使用 RP 实体从 python-fido2 库实例化
Fido2Server类。该服务器负责处理挑战生成、证明验证和断言校验。 - 配置证明偏好:设置证明传递偏好,以控制服务器是否请求认证器身份证明:
none:不请求证明(最简单,推荐大多数部署使用)indirect:可提供证明,但 CA 可能对其进行匿名化direct:来自认证器制造商的完整证明链enterprise:用于受管环境的设备标识证明
- 会话管理:配置服务器端会话,以在注册/认证流程的开始阶段和完成阶段之间存储 WebAuthn 状态。使用安全的、httponly 的 Cookie,并设置 SameSite=Strict。
- 凭据存储:设计数据库架构以存储凭据记录:
credential_id(二进制)、public_key(COSE 密钥)、sign_count(用于克隆检测的 uint32)、user_id、created_at、last_used、display_name和transports(USB、NFC、BLE、internal)。
步骤 2:注册仪式(凭据创建)
实现 WebAuthn 注册流程以创建新凭据:
- 开始注册:调用
server.register_begin(),传入用户实体(PublicKeyCredentialUserEntity,包含用户 ID、用户名和显示名称)、该用户已有凭据的列表(以防止重复注册),以及user_verification和authenticator_attachment的选项。 - 认证器选择条件:
authenticator_attachment: cross-platform限定为漫游认证器(USB/NFC 密钥)authenticator_attachment: platform限定为内置认证器(Touch ID、Windows Hello)- 省略此字段则允许两种类型
resident_key: required强制创建存储在认证器上的可发现凭据(通行密钥)user_verification: required强制在认证器上进行 PIN 或生物识别验证
- 客户端仪式:浏览器使用来自服务端的选项调用
navigator.credentials.create()。认证器生成新的密钥对,将私钥存储在其安全元件中,并返回公钥、凭据 ID、认证对象和客户端数据 JSON。 - 完成注册:调用
server.register_complete(),传入已保存的状态和客户端响应。服务端验证认证签名,提取凭据公钥和 ID,并返回包含待存储凭据数据的AuthenticatorData。 - 存储凭据:将
credential_data(包含credential_id、作为 COSE 密钥的public_key,以及sign_count)持久化到与该用户账户关联的数据库。
步骤 3:认证仪式(断言)
实现 WebAuthn 认证流程以验证凭据:
- 开始认证:调用
server.authenticate_begin(),传入该用户已注册凭据的列表(对于由认证器识别用户的可发现凭据流程,可省略此参数)。根据所需保证级别设置user_verification。 - 客户端断言:浏览器使用服务端选项调用
navigator.credentials.get()。认证器定位匹配的凭据,如有需要则执行用户验证,递增签名计数器,并使用私钥对挑战进行签名。 - 完成认证:调用
server.authenticate_complete(),传入已保存的状态、已注册凭据和客户端响应。服务端根据存储的公钥验证断言签名,并验证签名计数器已递增(克隆检测)。 - 更新签名计数:认证成功后,更新该凭据存储的
sign_count。如果新的签名计数不大于存储的值,则该密钥可能已被克隆——将此标记为安全事件。 - 可发现凭据流程:对于无密码认证,用户无需先输入用户名。认证器会展示该 RP ID 的所有可发现凭据,所选凭据的
userHandle可识别用户。
步骤 4:YubiKey 注册与管理
实现组织级 YubiKey 配置工作流:
- PIN 初始化:首次使用前,YubiKey 需要设置 FIDO2 PIN(最少 4 个字符,锁定前可重试 8 次)。通过 Yubico Authenticator 应用引导用户完成 PIN 设置,或通过 CTAP2
clientPin命令以编程方式完成。 - 主密钥注册:将用户的主 YubiKey 注册到其账户。使用便于识别的标签(例如 "USB-A YubiKey - Office")和认证器的 AAGUID 存储凭据,以便识别设备。
- 备用密钥注册:要求用户至少注册两把安全密钥。备用密钥应单独存放(家中、保险箱)。两把密钥必须注册到同一账户,以便任意一把均可完成认证。
- 密钥证明验证:对于企业部署,验证证明证书链以确认该密钥是来自 Yubico 的正品 YubiKey。将 AAGUID 与 Yubico 公布的值进行比对,以识别确切型号。
- 密钥生命周期管理:实现管理功能,用于列出用户已注册的密钥、吊销已泄露的密钥、强制重新注册,以及审计密钥使用模式(最后认证时间、认证总次数)。
步骤 5:Passkey 迁移策略
规划并执行从密码到 passkey 的迁移:
- 分阶段推出:先从自愿注册 passkey 开始,同时保留现有密码认证。跟踪采用指标(拥有 passkey 的用户百分比、使用 passkey 与密码登录的百分比)。
- 凭据升级流程:当用户使用密码认证时,提示其注册 passkey。在密码登录成功后立即显示 WebAuthn 注册对话框,以尽量减少阻力。
- 跨设备 passkey:为没有硬件安全密钥的用户支持同步 passkey(存储在平台凭据管理器中的 passkey,如 iCloud Keychain、Google Password Manager 或 1Password)。这些 passkey 无需专用硬件即可提供防钓鱼能力。
- 账户恢复:为丢失所有安全密钥的用户设计恢复流程:
- 在注册时生成的恢复代码(打印出来,存储在密码管理器中)
- 身份验证后由管理员监督重新注册
- 临时限时密码登录,并强制重新注册密钥
- 绝不允许仅通过电子邮件或短信进行恢复,因为这会破坏防钓鱼能力
- 密码弃用时间表:在 passkey 采用率超过目标阈值后,先对高权限账户强制实施仅 passkey 认证,然后扩展到所有账户。在过渡窗口期内保留密码作为后备方案。
- 监控与指标:跟踪注册成功率、认证失败率(密钥错误、超时、取消)、平均认证时间,以及 passkey 与密码登录的比率。
关键概念
| 术语 | 定义 |
|---|---|
| FIDO2 | W3C WebAuthn API 与 FIDO Alliance CTAP2 协议组合的统称,利用公钥密码学实现无密码且抗钓鱼的身份验证 |
| WebAuthn | W3C Web Authentication API,允许 Web 应用通过 navigator.credentials.create()(注册)和 navigator.credentials.get()(身份验证)创建并使用公钥凭据 |
| CTAP2 | Client to Authenticator Protocol 版本 2;浏览器(客户端)通过 USB、NFC 或 BLE 与外部验证器通信所使用的协议 |
| 依赖方(RP) | 请求身份验证的 Web 应用或服务;通过其 RP ID(域名)和 RP 名称(显示字符串)标识 |
| 可发现凭据(Passkey) | 存储在验证器上的凭据,无需 RP 提供凭据 ID 即可枚举,从而支持无用户名身份验证流程 |
| 认证声明(Attestation) | 验证器就其身份和属性提供的密码学证明;RP 使用它来验证验证器型号和制造商 |
| AAGUID | Authenticator Attestation Globally Unique Identifier;标识验证器型号的 128 位值(例如,所有 YubiKey 5 NFC 设备共享同一 AAGUID) |
| 签名计数器(Sign Count) | 由验证器维护并包含在每次断言中的单调递增计数器;RP 使用它来检测被克隆的验证器 |
| 用户验证(UV) | 在验证器本身上进行的本地身份验证(PIN、指纹、人脸识别),用于证明持有验证器的人就是合法所有者 |
工具与系统
- python-fido2:Yubico 官方 Python 库(v2.0+),提供用于依赖方实现的
Fido2Server,以及用于通过 USB 与验证器直接通信的CtapHidDevice/Fido2Client - YubiKey 5 系列:Yubico 硬件安全密钥,支持 FIDO2/CTAP2、U2F、PIV、OpenPGP 和 OTP;提供 USB-A、USB-C、NFC 和 Nano 外形规格
- py_webauthn:Duo Labs 的 Python WebAuthn 库,提供
generate_registration_options()、verify_registration_response()、generate_authentication_options()和verify_authentication_response()函数 - Yubico Authenticator:用于管理 YubiKey FIDO2 凭据、设置 PIN 和查看已注册账户的桌面和移动应用
- WebAuthn.io / demo.yubico.com:用于针对真实验证器验证 WebAuthn 注册和身份验证流程的在线测试工具
常见场景
场景:为开发团队部署 FIDO2 MFA
背景:一家软件公司希望为其 50 人的开发团队用硬件安全密钥替换基于 TOTP 的 MFA。开发人员拥有生产基础设施的 root 访问权限,是网络钓鱼攻击的高价值目标。该公司已统一采用 YubiKey 5 NFC。
方法:
- 配置 YubiKey 5 NFC 密钥(每位开发人员 2 个:主密钥 + 备用密钥),并使用防篡改包装分发,附上初始 PIN 设置说明
- 部署与公司 SSO(OAuth 2.0 / OpenID Connect)提供商集成的 WebAuthn 依赖方服务器,配置
authenticator_attachment: cross-platform和user_verification: required - 运行注册会话,让每位开发人员将两个密钥注册到其账户,并通过 attestation 验证确认真实的 YubiKey 5 NFC AAGUID
- 配置 SSO 提供商,要求所有开发人员账户将 FIDO2 作为第二因素,并提供 30 天宽限期,在此期间 TOTP 仍可用
- 实现密钥管理的自助门户:查看已注册密钥、注册替换密钥,以及报告丢失/被盗密钥(触发立即吊销凭证并重新注册)
- 宽限期结束后,为开发人员账户禁用 TOTP。监控认证日志中的任何回退尝试,并为剩余的未迁移人员提供 1:1 支持
- 实现开发团队 100% 采用 FIDO2,将生产基础设施访问的网络钓鱼风险降至接近零
陷阱:
- 未要求注册备用密钥,导致单个密钥丢失时账户被锁定
- 设置
user_verification: discouraged,允许任何实际持有密钥的人无需 PIN 即可认证 - 忘记验证签名计数器,错过克隆密钥攻击
- 不支持 NFC,影响主要使用平板电脑或手机工作的开发人员
- 允许 TOTP 作为永久回退方式,削弱 FIDO2 部署的抗网络钓鱼能力
场景:为客户面向的应用程序实现无密码登录
背景:一个电子商务平台希望为其 200 万用户提供基于 passkey 的无密码登录,作为密码的替代方案,以减少凭据填充和网络钓鱼导致的账户接管。
方法:
- 使用
resident_key: required实现 WebAuthn,创建可发现的凭证,实现无需用户名的登录 - 通过省略
authenticator_attachment,同时支持平台认证器(Touch ID、Windows Hello、Android 生物识别)和漫游认证器(安全密钥) - 在登录页面添加"使用 passkey 登录"按钮,触发带有空
allowCredentials列表的navigator.credentials.get(),提示认证器提供可用的 passkey - 成功创建 passkey 后,提示用户在第二台设备上创建 passkey 以实现冗余
- 在推广期间保留密码登录作为回退方式,并在每次密码登录后持续提示用户设置 passkey
- 跟踪指标:passkey 注册率(第一季度目标 30%)、passkey 与密码登录比例、认证失败率以及账户接管事件
- 6 个月后,为切换到仅使用 passkey 认证的用户提供激励(延长会话时长、减少 CAPTCHA)
陷阱:
- 未处理用户的平台认证器(例如笔记本电脑 Touch ID)不可用、需要通过二维码进行跨设备认证的情况
- 假设所有用户都有支持生物识别的设备;有些用户需要回退到基于 PIN 的验证
- 未为丢失所有已注册 passkey 访问权限的用户实现适当的账户恢复
- 忽视浏览器兼容性差距,尤其是 iOS 上较旧版本的 Safari
输出格式
## FIDO2 Deployment Report
**Application**: auth.example.com
**RP ID**: example.com
**Date**: 2026-03-19
### Enrollment Summary
- **Total Users**: 50
- **Users with Primary Key**: 50 (100%)
- **Users with Backup Key**: 47 (94%)
- **Authenticator Models**: YubiKey 5 NFC (48), YubiKey 5C NFC (2)
### Authentication Metrics (Last 30 Days)
- **Total Authentications**: 12,847
- **FIDO2 Authentications**: 12,203 (95.0%)
- **TOTP Fallback**: 644 (5.0%) -- grace period active
- **Mean Authentication Time**: 2.3 seconds
- **Authentication Failures**: 127 (0.99%)
- User cancelled: 89
- Timeout: 23
- Invalid signature: 12
- Sign count regression (possible clone): 3
### Security Events
- **Lost Key Reports**: 2
- User A: primary key lost 2026-03-12, revoked, backup promoted, new backup enrolled
- User B: backup key damaged 2026-03-15, revoked, replacement enrolled
### Credential Details
| User | Key Label | AAGUID | Registered | Last Used | Sign Count |
|------|-----------|--------|------------|-----------|------------|
| alice | YubiKey Primary | 2fc0579f... | 2026-02-15 | 2026-03-19 | 847 |
| alice | YubiKey Backup | 2fc0579f... | 2026-02-15 | 2026-03-01 | 12 |
| bob | YubiKey Primary | 2fc0579f... | 2026-02-16 | 2026-03-19 | 631 |
评论
支持 Markdown