如何使用node-cbor解码WebAuthN密钥的authenticatorData?
正确解码WebAuthn的authenticatorData(Node.js 18环境)
你遇到的报错核心原因是:authenticatorData和attestationObject的编码逻辑完全不一样。attestationObject是CBOR格式的字节流,所以能用cbor库解码;但authenticatorData是WebAuthn规范定义的固定结构二进制数据,既不是CBOR编码,也不能直接转utf-8解析,得按规范的字节结构来处理。
两种可行的解码方案
方案1:手动按WebAuthn规范解析
根据WebAuthn标准,authenticatorData的字节结构如下:
- 前32字节:RP ID的SHA-256哈希值
- 第33字节:标志位(flags),用二进制位表示各种状态(比如是否包含凭证数据、扩展数据等)
- 第34-37字节:签名计数器(大端序无符号32位整数)
- 可选扩展部分:如果flags的第6位(AT标志,0x40)为1,后面跟着凭证相关数据;如果第7位(ED标志,0x80)为1,最后跟着扩展数据
在Node.js 18里可以直接用Buffer来手动解析,示例代码:
function parseAuthenticatorData(authDataBuffer) { // 注意:这里的authDataBuffer需要是二进制Buffer,不是base64url字符串 const rpIdHash = authDataBuffer.subarray(0, 32); const flagsByte = authDataBuffer[32]; const flags = { userPresent: !!(flagsByte & 0x01), userVerified: !!(flagsByte & 0x04), hasAttestedCredentialData: !!(flagsByte & 0x40), hasExtensionData: !!(flagsByte & 0x80), }; const signCount = authDataBuffer.readUInt32BE(33); let offset = 37; let attestedCredentialData = null; if (flags.hasAttestedCredentialData) { const aaguid = authDataBuffer.subarray(offset, offset + 16); offset += 16; const credentialIdLength = authDataBuffer.readUInt16BE(offset); offset += 2; const credentialId = authDataBuffer.subarray(offset, offset + credentialIdLength); offset += credentialIdLength; const credentialPublicKey = authDataBuffer.subarray(offset); // 这里的公钥是CBOR格式,需要用cbor库解码 const decodedPublicKey = require('cbor').decodeAllSync(credentialPublicKey)[0]; attestedCredentialData = { aaguid, credentialId, credentialPublicKey: decodedPublicKey, }; } let extensionData = null; if (flags.hasExtensionData) { // 扩展数据是CBOR格式,用cbor库解码 extensionData = require('cbor').decodeAllSync(authDataBuffer.subarray(offset))[0]; } return { rpIdHash, flags, signCount, attestedCredentialData, extensionData, }; } // 使用示例:先把base64url格式的authenticatorData转成Buffer const authDataBase64Url = credential.response?.authenticatorData; const authDataBuffer = Buffer.from(authDataBase64Url, 'base64url'); const parsedAuthData = parseAuthenticatorData(authDataBuffer);
方案2:用成熟的WebAuthn库解析
手动解析容易出错,更推荐用专门的WebAuthn服务端库,比如@simplewebauthn/server,它已经封装好了所有解析逻辑:
- 先安装库:
npm install @simplewebauthn/server
- 用库解析的代码示例:
const { parseAuthenticatorData } = require('@simplewebauthn/server'); // 先把base64url转成Buffer const authDataBuffer = Buffer.from(credential.response?.authenticatorData, 'base64url'); const parsedAuthData = parseAuthenticatorData(authDataBuffer); // parsedAuthData里包含了所有解析好的字段:rpIdHash、flags、signCount、attestedCredentialData等
关键提醒
别再用cbor库去解码authenticatorData了——它从一开始就不是CBOR格式的数据,这才是你报错的根本原因。attestationObject之所以能解码,是因为它本身就是CBOR包裹的结构,里面才包含了authenticatorData这个二进制字段。
内容的提问来源于stack exchange,提问作者Doug Reeder
相关产品推荐
相关产品推荐

