我正在努力为新创建的网站添加 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 驱动程序定义的,但不清楚对应的驱动程序是什么。狩猎仍在继续……