WebAuthn:如何多次注册身份验证器

WebAuthn : how to register an authenticator several time

我正在使用 Yubico 演示来实现 webauthn 服务器:https://developers.yubico.com/WebAuthn/WebAuthn_Walk-Through.html

我已经实现了 CredentialRepository class 来替换 In Memory 以访问数据库。

目前我遇到了一个问题: 我希望能够使用此服务器,以便客户端可以使用 Yubikey(或 Andorid phone)连接到多个网站。我希望客户为每个站点注册他的密钥。问题是 Yubico 服务器不希望我们在服务器上多次注册相同的密钥,同时保持相同的 username.

是否可以通过使密钥注册取决于必须注册密钥的站点来源而不是 用户名 来解决此问题?

(我不想将 用户名 替换为数据库中理解问题的不同值)

欢迎所有想法。 谢谢。

阻止您为同一帐户多次注册身份验证器的原因在于依赖方发送的 PublicKeyCreationOptions。在 PublicKeyCreationOptions 中有一个字段 excludeCredentials(下面屏幕截图 link 中的第 22 行)。

PublicKeyCreationOptions Example

如果您尝试注册的凭据的凭据 ID 与列表中的任何项目相匹配,则 WebAuthn 仪式将不会完成请求。

为什么要这样做?

不熟悉 WebAuthn 工作原理的用户可能没有意识到他们只需要注册一次身份验证器,并且他们可以在多个设备上使用同一个身份验证器。困惑的用户可能会尝试在多个设备上注册安全密钥,并且可能会产生一种更麻烦的用户体验的感觉。这就是我们在一般指南中使用 excludeList 的原因。 以下是有关如何构建此列表的一些背景信息。

服务器如何创建此列表?

构建依赖方时,您pass in the userStorage which allows the rp object to talk to your database where you're storing the credentials. When you begin your registration request, you pass in the userID when you are building the PublicKeyCredentialCreationOptions object needed by the RegistrationRequest object. If you observe the rp.startRegistration method会看到通过在 userStorage 中搜索与发出请求的用户的用户 ID 相匹配的每个凭据来构建排除列表。

值得一提的是,我们的示例通常充当单个 origin/application 的依赖方,而您的示例处理多个。

在这种情况下,您有几个选择

这里有一些建议:

  • 向您的用户提供指导,指出他们可以使用相同的 account/authenticator 进入您的多个网站。这仅在您的依赖方充当单一来源身份验证服务时适用,然后将用户路由回他们来自的网站;例如,website1.com、website2.com 和 website3.com 中的用户都被路由到 my-relyingparty.com,经过身份验证,然后路由回其原始站点
  • 如前所述,java-webauthn-server 正在按用户名查找注册。您首先需要利用多个 rp objects,因为它们包含对特定来源的引用(您使用此 rp 对象创建的每个注册都将对应于您设置的 identity/origin)。您可以为每个原点创建 java-webauthn-server 的多个实例,或者在单个实例中创建逻辑以 1) 为每个原点创建多个 rp 对象,以及 2) 根据 java-webauthn-server 的原点动态选择要使用的 rp 对象用户要求。您可以选择通过重载 startRegistrations 方法以通过用户 ID 和 rp 进行搜索来跨多个服务器实例或 rp 利用相同的凭证存储库 ID/origin - 虽然这在技术上是可行的,但需要大量返工。
  • 选择不发送 excludeCredentials 列表中的现有凭据, 但这可能会让一些用户感到困惑

希望对您有所帮助

感谢@CodySalas 的有趣回答。

这就是我在你给我答案之前所做的事情:我让客户发回我 startRegistrationstartAuthentication 步骤的客户来源。 我在 InMemoryRegistrationStorage 中添加了一个 trackedOrigin 变量,并为这两个步骤设置了 trackedOriginuserStorage.setTrackedOrigin(origin)。 因此,当依赖方想要使用“getCredentialIdsForUsername()”搜索排除的凭据 (excludeCredentials) 时,它将检查 trackedOrigin 以便能够根据来源在数据库中发出请求。因此,用户名不再是唯一性约束,因为 excludeCredentials 将仅具有具有相同 username 和相同 origin.

的密钥的凭据

既然我看到了你的回答,我想重新考虑我找到的解决方案,因为我发现 RP ID 必须与客户端的域完全相同,而将使用 webauthn 服务器的站点将不会有所有相同的域...这是有问题的,但这是另一个问题。 我可能会为此打开另一个问题。