You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 20:06:04