Flask应用中Yubikey凭据JSON存储及反序列化认证报错解决
解决fido2 AttestedCredentialData序列化/反序列化JSON时的"Not Enough Data to Unpack"错误
问题原因
JSON仅支持序列化基本数据类型(字符串、数字、列表、字典),而AttestedCredentialData对象包含自定义类型(AAGUID)和字节类型(credential_id、公钥中的-2/-3字段)。直接将该对象序列化到JSON会导致数据格式损坏或丢失,反序列化时无法还原出完整的字节流供fido2的unpack()方法解析,从而抛出"Not Enough Data to Unpack"错误。
解决方案:正确序列化与反序列化
利用fido2库内置的pack()/unpack()方法处理对象的字节流转换,再通过Base64编码将字节流转为JSON可存储的字符串。
1. 注册时:序列化并存储到JSON
import json import base64 from fido2.ctap2 import AttestedCredentialData # 假设已获取注册流程返回的attested_credential_data对象 attested_credential_data = ... # 将AttestedCredentialData转为标准字节流 acd_bytes = attested_credential_data.pack() # 字节流转Base64字符串(确保JSON可存储) acd_b64 = base64.b64encode(acd_bytes).decode('utf-8') # 存储到JSON文件(关联用户名) user_data = { "username": "example_user", "registered_credential": acd_b64 } with open("users.json", "w") as f: json.dump(user_data, f)
2. 登录时:从JSON取回并反序列化
import json import base64 from fido2.ctap2 import AttestedCredentialData # 读取JSON中的用户数据 with open("users.json", "r") as f: user_data = json.load(f) # 解码Base64字符串为字节流 acd_b64 = user_data["registered_credential"] acd_bytes = base64.b64decode(acd_b64) # 反序列化为AttestedCredentialData对象 attested_credential_data = AttestedCredentialData.unpack(acd_bytes) # 后续可使用该对象完成认证流程
备选方案:拆解字段存储(调试场景)
如果需要单独存储各个字段,可拆解对象并将所有字节类型转Base64:
# 序列化 user_data = { "username": "example_user", "aaguid": str(attested_credential_data.aaguid), "credential_id": base64.b64encode(attested_credential_data.credential_id).decode('utf-8'), "public_key": { k: base64.b64encode(v).decode('utf-8') if isinstance(v, bytes) else v for k, v in attested_credential_data.public_key.items() } } # 反序列化 from fido2.utils import AAGUID from fido2.cose import CoseKey aaguid = AAGUID.from_string(user_data["aaguid"]) credential_id = base64.b64decode(user_data["credential_id"]) public_key_dict = { int(k): base64.b64decode(v) if isinstance(v, str) else int(v) for k, v in user_data["public_key"].items() } public_key = CoseKey.from_dict(public_key_dict) attested_credential_data = AttestedCredentialData(aaguid, credential_id, public_key)
关键注意事项
- 必须使用
fido2官方提供的pack()/unpack()方法处理AttestedCredentialData对象,确保字节流符合CTAP2协议规范。 - 所有字节类型数据必须通过Base64编码转为字符串后再存入JSON,避免直接序列化bytes导致的格式错乱。
- 不要手动修改或拼接
AttestedCredentialData的字节流,否则会破坏协议结构,导致解析失败。
内容的提问来源于stack exchange,提问作者Krithick
相关产品推荐
相关产品推荐

