如何在Web浏览器中通过WebAuthn/CTAP HMAC-Secret扩展获取对称密钥
从WebAuthn hmac-secret扩展提取对称密钥的实现方案
核心问题排查
你代码存在三处错误导致无法拿到密钥:
hmacGetSecret的salt1参数要求必须为32字节的Uint8Array类型,你传入的16位字符串不符合规范,会导致扩展不返回结果- 扩展返回的对称密钥不在
authenticatorData原始缓冲区内,需要调用getClientExtensionResults()方法获取扩展输出 - 注册凭证时必须主动开启
hmacCreateSecret扩展,否则后续无法获取派生密钥
可运行完整代码示例
凭证注册阶段(必须先执行,开启hmac-secret支持)
const createCredentialArgs = { publicKey: { rp: { name: "你的应用名称" }, user: { id: crypto.getRandomValues(new Uint8Array(16)), name: "用户名", displayName: "用户显示名" }, challenge: crypto.getRandomValues(new Uint8Array(32)), pubKeyCredParams: [{ type: "public-key", alg: -7 }], timeout: 60000, // 关键:注册时开启hmac-secret扩展 extensions: { hmacCreateSecret: true } } }; navigator.credentials.create(createCredentialArgs) .then((cred) => { // 这里需要保存返回的cred.rawId作为后续登录的allowCredentials参数 console.log("凭证注册成功,凭证ID:", cred.rawId); }) .catch(err => console.error("注册失败:", err));
密钥获取阶段
// 替换为你注册阶段保存的凭证ID const myCredentials = [{ type: "public-key", id: 你保存的凭证ID, // 类型为Uint8Array transports: ["usb", "nfc", "ble"] }]; // 生成32字节合法salt,也可通过业务固定字符串做SHA-256哈希得到固定salt const salt1 = crypto.getRandomValues(new Uint8Array(32)); const getCredentialDefaultArgs = { publicKey: { timeout: 60000, allowCredentials: myCredentials, challenge: crypto.getRandomValues(new Uint8Array(32)), extensions: { hmacGetSecret: { salt1: salt1 } } } } navigator.credentials.get(getCredentialDefaultArgs) .then(async (assertion) => { // 从扩展结果中提取对称密钥 const extResults = assertion.response.getClientExtensionResults(); if (extResults.hmacGetSecret?.output1) { // output1即为你需要的32字节对称密钥,类型为Uint8Array const symmetricKey = extResults.hmacGetSecret.output1; console.log("获取对称密钥成功:", symmetricKey); // 可选:导入为Web Crypto API可用的AES密钥 const aesKey = await crypto.subtle.importKey( "raw", symmetricKey, { name: "AES-GCM" }, false, ["encrypt", "decrypt"] ); console.log("AES密钥导入完成:", aesKey); } else { console.error("hmac-secret扩展未生效,请确认注册时已开启扩展且硬件密钥支持该功能"); } }) .catch((err) => { console.log("断言获取失败:", err); });
补充注意事项
- 测试时不要使用浏览器无痕/隐私模式,该模式下默认禁用WebAuthn扩展功能
- YubiKey 5全系列默认支持hmac-secret扩展,无需额外配置
- 相同的salt每次会派生相同的对称密钥,你可以根据业务场景设置固定salt实现同一密钥重复获取
内容的提问来源于stack exchange,提问作者ucipass
相关产品推荐
相关产品推荐

