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

使用Fido2.AspNet实现无密码登录时遇挑战不匹配异常

解决Fido2.AspNet注册时"Authenticator response challenge does not match original challenge"异常

问题场景

使用Fido2.AspNet 4.0.0-beta.16实现无密码登录注册流程时,调用MakeNewCredentialAsync验证前端返回的凭证响应时抛出异常:

Authenticator response challenge does not match original challenge

流程步骤:

  1. 服务器调用fido2.RequestNewCredential生成注册选项,存入Redis缓存后返回给Angular前端
  2. 前端通过@ownid/webauthn的fido2Create方法处理选项,将返回结果的data字段传回服务器
  3. 服务器从Redis取出缓存选项,构造MakeNewCredentialParams并调用MakeNewCredentialAsync时触发异常

相关代码:

服务器端验证代码

var options = await cache.GetStringAsync(...);

var makeNewCredentialParams = new MakeNewCredentialParams {
    AttestationResponse = request.AttestationResponse,
    IsCredentialIdUniqueToUserCallback = ...,
    OriginalOptions = CredentialCreateOptions.FromJson(options)
};

var credential = await fido2.MakeNewCredentialAsync(makeNewCredentialParams, cancellationToken);

Angular前端代码

async register(email: string) {
    const response = await lastValueFrom(this.#http.post('account/registerStart', email))
    const fido = await fido2Create(response, email)

    return await lastValueFrom(this.#http.post('account/registerEnd', { email, attestationResponse: fido.data })) as string
}

可能原因及解决方案

1. Challenge编码/解码格式不一致

FIDO2规范中Challenge通常以Base64URL格式传递,但服务器生成的CredentialCreateOptions.Challenge是byte[]类型,序列化到JSON时会转为Base64字符串。若前端传回的Challenge是Base64URL格式,直接反序列化会导致字节数组不匹配。

解决方法:

  • 手动校验前后端Challenge一致性:生成选项时记录Challenge的Base64和Base64URL格式;前端传回响应后,将Challenge从Base64URL解码为byte[],与原始Challenge对比。
  • 服务器端解析前端传入的Challenge时使用Base64URL解码:
    // 将前端传入的Base64URL格式Challenge转为byte[]
    var incomingChallenge = Base64UrlTextEncoder.Decode(request.AttestationResponse.Challenge);
    var originalChallenge = OriginalOptions.Challenge;
    
    // 提前校验便于排查问题
    if (!incomingChallenge.SequenceEqual(originalChallenge))
    {
        // 记录日志输出两个Challenge的Base64值,定位差异
        throw new InvalidOperationException("Challenge mismatch detected");
    }
    

2. Redis缓存的选项序列化/反序列化错误

若存入Redis的CredentialCreateOptions序列化方式不正确,会导致反序列化后的Challenge值被篡改。

解决方法:

  • 序列化时使用正确的JSON配置,确保byte[]类型的Challenge被正确序列化为Base64字符串:
    // 存入Redis时的序列化代码
    var options = fido2.RequestNewCredential(...);
    var optionsJson = JsonSerializer.Serialize(options, new JsonSerializerOptions { 
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        WriteIndented = false
    });
    await cache.SetStringAsync(cacheKey, optionsJson);
    
  • 取出缓存后,验证CredentialCreateOptions.FromJson(options)得到的OriginalOptions.Challenge是否与生成时一致(可打印两者的Base64值对比)。

3. 缓存Key匹配错误

若Redis缓存使用的Key与当前用户不绑定,会取出其他用户的注册选项,导致Challenge不匹配。

解决方法:

  • 缓存Key与用户强绑定,比如使用$"fido2:register:{userId}"作为Key,确保每个用户的注册选项独立存储。

4. Beta版本已知问题

使用的4.0.0-beta.16属于测试版本,可能存在未修复的Bug。

解决方法:

  • 查看Fido2.AspNet的Release Notes,确认该版本是否存在Challenge校验相关的已知问题,尝试升级到最新稳定版或更高版本的Beta版。

内容的提问来源于stack exchange,提问作者Gargoyle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:26:14