最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
不透明:可互操作的密钥记录和 Go API
时间:2026-07-21 17:51:49 编辑:袖梨 来源:一聚教程网
万能钥匙是目前信息安全领域最重要的事情,因为它们是应对网络钓鱼攻击的唯一原则性解决方案。就像内存安全是解决内存损坏攻击的唯一原则性解决方案一样。

不幸的是,在服务器端实现它们可能比使用密码哈希更复杂。其中一部分是不可避免的,因为密钥需要与浏览器交互才能获得其网络钓鱼防御属性。然而,通过定义可互操作的密钥记录编码,可以更有效地抽象出其中的一部分。
WebAuthn 规范将凭证记录定义为一个抽象概念,包含许多组件,例如 type 、 id 、 publicKey 、 backupState 、 Transports 和其他标志。 Google 建议使用具有 Credential ID 主键、 public_key 、 backed_up 和 Transports 列的数据库表。 Adam Langley 的精彩 WebAuthn 之旅同样建议使用 cred_id 主键,以及单独的 public_key_spki 和 backed_up 列。
所有指南都建议使用库来处理 WebAuthn 身份验证,但这仍然使应用程序具有潜在的不可互操作的数据库架构。将整个身份验证流程和数据库交互推迟到库或框架也可能是不切实际的。
应用程序可以将可互操作的、明确指定的密钥记录作为不透明字符串(如密码哈希)进行处理,可以成为中间抽象层。
c2sp.org/passkey-record 是一项规范提案,它借用了密码哈希竞争 (PHC) 字符串的语法,并在大部分工作中重用现有的验证器数据编码。一条记录看起来像这样:
有效负载是身份验证器数据,是大多数凭证记录字段的 CTAP2 CBOR 编码,已由 WebAuthn 指定并包含在 AuthenticatorAttestationResponse 的 JSON 编码中(这是 navigator.credentials.create() 的返回类型,即使未使用证明)。传输是唯一缺失的字段,它们存储为 PHC 参数。
然后,应用程序只负责跟踪与用户帐户关联的密钥记录,这是 Web 开发人员熟悉的任务,因为它与实现密码身份验证没有什么不同(除了每个帐户有多个密钥)。这些不透明字符串可以传递到库以验证登录断言(或使用适当的 exceptedCredentials 生成注册请求)。
通过明确指定的可互操作存储格式,有望在保留凭证数据库的同时切换密钥库(甚至后端语言)。
您可能想要存储的其他字段
除了密钥记录之外,应用程序可能仍然希望存储元数据字段,例如用户选择的昵称以及创建和上次使用时间戳,以提供漂亮的密钥管理 UI。这些都不需要 WebAuthn 库进行任何特殊处理。
一个例外是备份状态标志。密钥向服务器报告它们是否已备份(例如备份到 iCloud 钥匙串或 Google 帐户),并且服务器可以使用该信号建议从帐户中删除密码。该标志可以在登录时更改,而密钥记录是不可变的,因此必须单独存储并在每次登录时更新。我认为这种逻辑对于一般网站来说被高估了,无论如何,该网站都会继续支持电子邮件密码重置。
潜在的加密/密钥 API
在这些密钥记录的基础上,我起草了一个潜在的加密/密钥无状态 Go 包 API。
注册流程为
- 使用登录(或以其他方式识别)的用户详细信息和任何现有的密钥记录调用 RelyingParty.NewRegistration
- 将返回的 JSON 传递给 parseCreationOptionsFromJSON(),然后传递给 navigator.credentials.create()
- 将返回的 JSON 编码的 PublicKeyCredential 传递给 RelyingParty.Register
- 将返回的密钥记录存储在数据库中
登录流程是
- 生成登录页面时调用 RelyingParty.NewLogin
- 将返回的请求存储在具有短 TTL 的键值缓存中,位于 RequestID(request) 下,并将返回的 JSON 传递给 parseRequestOptionsFromJSON() ,然后传递给 navigator.credentials.get()
- 将返回的 JSON 编码的 PublicKeyCredential 传递给 Inspect ,并使用返回的 requestID 从键值缓存中检索请求,并使用返回的 userID 从数据库中检索密钥记录
- 将 JSON PublicKeyCredential、请求和密钥记录传递给 RelyingParty.Login
该应用程序负责
- 将不透明、永久、保护隐私的用户 ID 与每个用户相关联;
- 存储与用户相关的密钥记录;和
- 由 RelyingParty.NewLogin 产生的缓存请求挑战。
该库提供可以直接传递给 parseCreationOptionsFromJSON() 和 parseRequestOptionsFromJSON() 的 JSON 值,并接受通过在 PublicKeyCredential 上调用 JSON.stringify() 返回的 JSON 值。
这是针对可发现的凭证流(也称为密钥,身份验证器存储并向服务器提供用户 ID)进行了优化,但 RelyingParty.NewLoginForUser 方法也可用于第二因素流或重新身份验证提示。该 API 适用于模态和条件 UI(自动填充)流。
有一些帮助程序可以从密钥记录( AAGUID 、 BackedUp )和 JSON 编码的 PublicKeyCredential ( ResponseBackedUp )中提取信息。
目前尚未实施;在可能提出 Go 1.28 提案之前,我希望获得有关密钥记录格式和 Go API 的反馈。
关于重复的凭证 ID
使用此存储模型不能做的一件事是确保不同的帐户不会共享具有相同凭证 ID 的密钥,而规范规定您应该这样做。
进行该检查的原因是避免攻击,即您通过 ID 查找凭证并发现错误的公钥或用户 ID,因为攻击者故意通过自己的帐户注入冲突的凭证 ID。
如果您一开始就没有凭证 ID 索引,则这种攻击根本不可能发生!仅需要索引来减轻因索引的存在而引入的攻击。
登录尝试携带用户 ID,如果您使用它来查找用户的密钥记录来验证登录,则其他用户是否拥有具有相同凭据 ID 的密钥并不重要,就像两个用户共享密码并不重要一样。
不要让攻击者决定您的主键,这样您就不会遭受主键冲突攻击。
如需更多 Go API 预览,请在 Bluesky 上关注我(@filippo.abyssdomain.expert)或在 Mastodon 上关注我(@[email protected])。
图片
来自今年 CENTOPASSI 的更多内容(一项 GPS 追踪摩托车比赛,涉及精心策划、100 个坐标以及三天半时间内 1700 公里的二级公路)。这是从荒无人烟、仍然白雪皑皑的 Campo Imperatore 爬下来后,看到的蒙特堡 (AQ)。
我的工作是由 Geomys 实现的,Geomys 是一个由专业 Go 维护者组成的组织,由 Ava Labs、Teleport、Datadog、Tailscale 和 Sentry 资助。通过我们的聘用合同,他们确保了我们开源维护工作的可持续性和可靠性,并可以直接了解我和其他 Geomys 维护人员的专业知识。 (在 Geomys 公告中了解更多信息。)以下是其中一些人的几句话!
Teleport — 在过去的五年里,攻击和危害已经从传统的恶意软件和安全漏洞转向通过社会工程、凭据盗窃或网络钓鱼来识别和危害有效的用户帐户和凭据。 Teleport Identity 旨在通过访问监控消除弱访问模式,最大限度地减少访问请求的攻击面,并通过强制访问审查清除未使用的权限。
Ava Labs — Ava Labs 是 AvalancheGo(与 Avalanche 网络交互时使用最广泛的客户端)的维护者,我们相信开源加密协议的可持续维护和开发对于区块链技术的广泛采用至关重要。我们很自豪能够通过对 Filippo 及其团队的持续赞助来支持这项必要且有影响力的工作。
相关文章
- 检疫区最后一站结膜炎与红眼区别一览 07-21
- 超大杯研究员的异常求汁欲第二章流程及单词出处 07-21
- 斗罗大陆诛邪传说什么时候上线 07-21
- 原神八重神子选精通沙还是攻击沙好 07-21
- 我不是盐神网站入口在哪 07-21
- 冒险者旅馆2全流程通关攻略是什么 07-21