SimpleWebAuthn 把 WebAuthn 拆成两个包:@simplewebauthn/browser 封装 navigator.credentials,@simplewebauthn/server 生成依赖方发送的选项,并验证返回的内容——证明格式、COSE 密钥、计数器和签名。本次检查用一个软件认证器驱动服务端包,该认证器生成标准的注册和断言 JSON,与 Python、Go 和 Java 页面所用的字节相同。
最常见的集成缺陷是选项所要求的与验证所要求的不一致。generateRegistrationOptions() 默认使用 userVerification: "preferred",但两个验证器都默认 requireUserVerification: true:认证器只证明了用户在场时——例如没有设置 PIN 的安全密钥——其断言被拒绝,报错 User verification required, but user could not be verified。应一次性做出决定,并像示例那样让两端的设置保持一致。
按照 WebAuthn 规范的要求,ES256 的断言签名必须是 ASN.1 DER。64 字节的原始 r‖s 签名照样会被送进 ASN.1 解析器,报出的消息取决于签名字节——在 60 个新建凭证上最常见的是 Too big integer、End of input reached before message was fully decoded 或 Data does not match to ECDSASigValue ASN1 schema.——这些消息都没有提到编码。认证器和通行密钥提供方生成的都是 DER,因此出现原始签名通常意味着客户端是手写的,或者测试工具直接调用了 WebCrypto 的 sign();可以用 DER ⇄ 原始格式转换器转换这些签名。high-S 的 DER 签名验证通过。
签名计数器低于已存储的值会被视为错误,而不是警告:验证时抛出了 Response counter value 3 was lower than expected 5,已存储值为 5 时,计数器为 0 也同样失败。只有一直报告 0 的凭证——同步通行密钥就是如此——才能以 0 通过。应保存收到的计数器值,并自行决定回退是锁定该凭证,还是只发出告警。14 版在默认的 pubKeyCredParams 中把 ML-DSA-44(COSE -48)列在第一位,排在 Ed25519(-8)、ES256(-7)和 RS256(-257)之前,Ed25519 凭证也完成了端到端验证。
用 WebAuthn 查看器解码浏览器实际发送的数据,在通行密钥沙盒中无需真实认证器即可试用各个流程,并用 AAGUID 查询按 AAGUID 识别认证器型号。