我刚刚开始在本地主机上玩
WebAuthn
。我了解到在 credentials.response.signature
中找到的签名值是签名 credentials.response.clientDataJSON
。然而,对于 navigator.credentials.get
的相同输入/挑战,我似乎得到了不同的签名。我最好的猜测是有一个时间戳或计数器进入签名值的某处?
我似乎无法解码
signature
或 authenticatorData
,这确实可以帮助我想象内部发生的事情。我可以按如下方式解码 clientDataJSON
,任何人都有示例代码,我可以用它来解码上述其他两个参数吗?
String.fromCharCode.apply(null, new Uint8Array(credentials.response.clientDataJSON))
我还发现在解码时
clientDataJSON
我偶尔会在Chrome中得到额外字段,这对我的用例来说有点烦人。
我的目标是让用户每次验证相同的
PublicKeyCredential
时都生成相同的签名或哈希值。有没有办法做到这一点?或者在 WebAuthn 范围内或其范围之外是否有其他方法可以从生物识别身份验证中受益,通过这些方法我可以从相同的输入生成相同的签名或哈希值?
请原谅我对
WebAuthn
可能有的任何误解,我对这项令人惊叹的技术还很陌生。我完全理解这不是 WebAuthn
的最初预期用途,因此可能需要一个简单的解决方法。
我的目标是让用户每次验证相同的签名或哈希时都生成相同的签名或哈希值
。PublicKeyCredential
这实际上是一个非常坏主意。使用随机挑战对消息进行签名的全部目的是避免重放攻击。否则,如果攻击者以某种方式拦截身份验证消息,则可以简单地重复使用该消息来冒充用户。
我了解到
中找到的签名值正在签名credentials.response.signature
credentials.response.clientDataJSON
这不准确。签名标志
authenticatorData + SHA256(clientDataJSON)
.
两者都是可变的。
authenticatorData
包含一个“计数器”,每次使用凭证密钥进行身份验证时都会增加,并且 clientDataJSON
应该(或 必须 为了安全)包含随机服务器端生成的质询。
我似乎无法解码签名或authenticatorData,这确实可以帮助我可视化内部发生的情况。我能够按如下方式解码 clientDataJSON,任何人都有示例代码,我可以用它来解码上述其他两个参数吗?
签名无法“解码”,只能在有足够的公钥的情况下“验证”。对于其他参数
authenticatorData
和clientDataJSON
,请查看底部的以下链接,它将对其进行解码。
https://webauthn.passwordless.id/demos/playground.html
我还发现在解码 clientDataJSON 时,我偶尔会在 Chrome 中得到额外的字段,这对我的用例来说有点烦人。
我不确定,我相信这与localhost测试有关。
如果您想要与凭证关联的少量固定数据,那么您可能希望研究 credBlob 或 prf 扩展。然而,并非所有身份验证器都会支持它们。更多人将支持
prf
,但 对 Chromium 的支持 几个月后才会出现。所以这里还没有一个很好的答案,但它可能比尝试修复签名更好。
所以,首先,一般来说,当您使用相同的数据作为输入时是否会产生相同的签名,这取决于所使用的签名方案。检查这个问题https://crypto.stackexchange.com/questions/26974/他们讨论这个问题。
现在,回到WebAuthn(假设您使用签名算法,对于相同的输入将生成相同的签名)让我们看看签名是如何生成的。这是我的虚拟身份验证器中的一个小代码,负责生成 WebAuthn 签名:
let authData = this._concatUint8Arrays(
rp_id_hash,
flags,
sign_count, // The signature counter will always increase
this._getAAGUID(),
credential_id_length,
credential_id,
cose_key
);
// Attestation object
let attestation_object = {'fmt': 'none', 'attStmt': {}, 'authData': authData};
// ...
// Generate signature
let client_data_hash = new Uint8Array(await crypto.subtle.digest('SHA-256', client_data));
let signatureData = this._concatUint8Arrays(authData, client_data_hash);
let signature = await Algorithms.Sign(this.private_key, signatureData);
您会注意到要签名的数据包括身份验证器的签名计数器,每次使用身份验证器时该计数器都会增加。这有助于检测重放攻击或克隆身份验证器攻击(更多信息此处)。
因此,生成相同的签名是不可行的。
如果您想更多地了解 WebAuthn 背后发生的事情,您可以查看我的 WebDevAuthn 项目 和 浏览器扩展,它允许您检查 WebAuthn 请求和响应。
通过简单的 hack,您可以在不使用任何服务器请求的情况下将数据存储在 webAuthN 中,并安全地恢复。
因此您可以创建一个秘密,将其存储在那里,并在以后检索它。
我在我的问题中为其编写了一个演示代码:
将数据存储到 webAuthN userHandle 有多糟糕?
不确定它的安全影响或我在这个解决方案中缺少的任何内容,并等待一些聪明的人对此给出明确的答案。