0

我正在努力为新创建的网站添加 WebAuthn 支持,并且在 navigator.credentials.get() 调用期间遇到了问题。客户端是 Fedora 33 上的 Firefox 85.0。如果重要,服务器是 Fedora 33 上的 Apache httpd。令牌是 Yubikey 4 或 Yubikey 5NFC(结果相同)。这是进行 API 调用的函数。显然,这里硬编码的凭证 ID 用于测试,而不是最终产品的一部分:

function handleUserAuthenticationResponse(r) {
  var cid1 = {type: "public-key", id: base64ToArrayBuffer("gL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCg==")};
  var cid2 = {type: "public-key", id: base64ToArrayBuffer("tjW1RPqtAJm69I/qeV7eRFJx6h87J3NPeJ/hhbkjttcCc2BWHQ2v2nueoKBSGabw1eYsT8S+lhJv1l1mYWX+Uw==")};
  var options = {
    rpID: "http://localhost",
    challenge: base64ToArrayBuffer(r.challenge),
    allowCredentials: [cid1,cid2],
    timeout: 60000
  };

  if (!window.PublicKeyCredential) {
    throw new Error("Unable to access credentials interface");
  }
  navigator.credentials.get({"publicKey":options})
    .then(assertion => handleTokenAssertion(assertion))
    .catch(e => {console.log("Error fetching token assertion:",e);});
}
function base64ToArrayBuffer(base64) {
    var binary_string = window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}
function handleTokenAssertion(a) {
  alert("Got an assertion!");
}

一切似乎都正常,Yubikey LED 闪烁,我按下触摸板,但随后我得到一个异常:

Error fetching token assertion: DOMException: An attempt was made to use an object that is not, or is no longer, usable

这似乎有点像 Firefox 的包罗万象。它可能表明令牌与 allowedCredentials[] 之一或其他内容不匹配。很难说。Yubikey 上的 FIDO2 凭证是使用与 libfido2 源打包的 fido2-cred(1) 工具创建的。在这种情况下,credentialId 来自fido2-cred -M输出:

CuCEGL10uPhBmNCY4NsGaAz0gir/68UMGFQn0pfb6tc=
http://localhost
fido-u2f
WMSGBbi6CMINQvnkVRUYcYltDg3pgFlihvtzbRHuwBPipEEAAAAAAAAAAAAAAAAAAAAAAAAAAABAgL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCqUBAgMmIAEhWCA5itRRCBO0lnsztvPvI1waVZLBCZ1XMJjOvlN2oZmBCyJYILFaRjThs5Paj1sOp81iID1LpUBYHJhp4dizC0eI/RrE
gL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCg==
MEQCIFfs8PagKhNnDgzxfurVzdkTDVTT6ixKk0ak/2qrbSPUAiAf64w390rX1cyY58JgSC/Ac97w6TLcYKuqxOSn5lxV0g==
<long assertion certificate>

您可以在第 5 行看到 credentialId,它cid1在 Javascript 函数中匹配。此外,如果我使用此 credentialId 从令牌请求断言,并且所有其他相同(除了挑战)与fido2-assert -G,一切正常:我得到断言并使用fido2-assert -V.

如果没有更有意义的诊断,很难知道要尝试什么,所以我想我会在这里问一下,看看是否有人有任何提示。也许我在使用 Javascript 或凭证 API 时犯了一些基本错误?

谢谢!

更新:我认为值得尝试的一种可能性是从 RP ID 中删除该方案,但这没有任何区别。

更新:查看 firefox 源代码,错误显然是 NS_ERROR_DOM_INVALID_STATE_ERR,它涵盖了几种不同的情况,但在这种情况下很可能是 U2F_ERROR_INVALID_STATE 的翻译(在 dom/webauthn/U2FHIDTokenManager.h 中)。反过来,U2F_ERROR_INVALID_STATE 在 third_party/rust/authenticator/src/u2fhid-capi.h 中定义为一个简单的数值 (3),没有说明该值的来源。也许它是由 Yubikey 的底层 HID 驱动程序定义的,但不清楚对应的驱动程序是什么。狩猎仍在继续……

4

1 回答 1

0

事实证明,问题确实是依赖方 ID 的格式。基于来自网络的示例代码(可能已与其他浏览器或代码版本一起使用?),我最初使用完整的 scheme://domain 格式作为 rpID(所以在我上面的代码中http://localhost),但事实证明所需要的只是域(localhost)。以这种方式修改 rpID 可以使断言过程成功。

最初我认为这不起作用,但事实证明我只是忘记提交更改。迟到了,它起作用了。

于 2021-02-09T07:55:46.773 回答