代表性面试主题

前端面试:如何安全灰度 WebAuthn 条件式创建?

前端困难
Offer.cc 编辑团队发布 更新

题干

你要在已有密码登录页中灰度 WebAuthn 条件式创建,让浏览器在用户输入账号时提示创建 passkey。如何设计前端能力检测、服务端验证和失败回退?

题干与适用场景

产品已有用户名、密码和条件式获取的 passkey 登录。现在希望在用户完成一次高信任登录后,利用 WebAuthn Level 3 的 conditional create 在不打断流程的情况下建议创建 passkey。请说明浏览器能力检测、创建条件、服务端校验、隐私边界和回滚策略。

题目聚焦 Web 平台与认证交互。不要把“浏览器支持 API”当成“用户设备一定有可用验证器”;创建仍需经过用户同意和服务端验证。

面试官考察点

  • 能否区分 conditional create、conditional get 和显式按钮创建。
  • 能否在能力、策略、用户状态和跨设备同步之间建立清晰的门槛。
  • 能否避免重复创建、误绑定账号、泄露凭据存在性或让失败阻塞密码登录。
  • 能否设计可观测的灰度和撤回,而不是把新 API 一次性打开。

强回答会把条件式创建当作增强路径:能力检测失败或用户拒绝时主流程不变,服务端仍验证 challenge、origin、RP ID 和用户归属。

回答前需要澄清的问题

  1. 目标是所有已登录用户,还是只针对已验证邮箱、完成 MFA 或高风险操作后的用户?
  2. 是否允许创建多台设备同步的 passkey?账户恢复和撤销策略会因此改变。
  3. 当前前端是否已经有一个未完成的 credentials.create() 请求?并发请求会产生难以解释的提示。
  4. 浏览器不支持 conditional create 时,是否显示显式“创建 passkey”按钮,还是完全隐藏?

30 秒回答框架

“我先用 WebAuthn 能力检测确认浏览器支持 conditional create,再结合账号状态、最近认证强度和服务端 feature flag 决定是否尝试。前端只在用户明确允许的时机发起一次创建,并用 AbortController 取消重复请求;任何不支持、取消或超时都回到原登录流程。服务端为一次性 challenge 绑定用户、origin、RP ID 和过期时间,验证成功后才保存 credential。灰度观察创建成功率、取消率、重复凭据、登录回退率和恢复工单;异常时关闭 flag,已创建的凭据仍可单独撤销。”

分步骤深入解答

1. 区分两种条件式交互

conditional get 让用户在输入账号时选择已有 passkey;conditional create 则是在表单上下文中建议创建新凭据。两者都依赖浏览器与验证器能力,不能只检查 PublicKeyCredential 对象就断言可用。

能力检测结果只决定是否尝试,不决定是否授权。服务端仍应把注册挑战绑定到当前已认证用户,并记录创建来源和策略版本。

2. 设计创建门槛

建议同时满足:浏览器报告 conditional create 能力;用户已完成足够强度的认证;账户未处于恢复、合并或高风险变更;服务端 feature flag 对该租户和流量窗口开放。对新设备可先显示解释文案,再由用户继续,而不是在页面加载时静默创建。

3. 防止重复与竞态

每个页面会话最多有一个创建请求。开始新请求前取消旧请求,组件卸载时也取消。服务端 challenge 使用一次即失效,credential ID 设唯一约束;重复提交返回幂等结果,不创建第二条记录。

text
capability -> policy gate -> one challenge -> user consent
      |            |               |
   fallback   feature flag     server verify -> persist

4. 完整验证注册结果

服务端验证 challenge、origin、RP ID、签名、用户句柄、attestation 策略和 credential ID。不要只相信前端返回的“创建成功”。如果不需要设备证明,可采用更简单的 attestation 策略,但必须说明这是隐私与风控权衡。

5. 处理同步与恢复

多设备同步的 passkey 让用户换设备后仍可能看到凭据,但同步不等于账户恢复。提供查看设备、撤销单个 credential、失去所有设备后的恢复流程;不要把是否存在 passkey 暴露给未认证请求。

6. 灰度和可观测性

按浏览器、平台、租户和风险等级分批打开。记录能力检测通过率、创建提示出现率、用户同意率、验证失败原因、取消/超时、重复 credential、密码回退率和支持工单。指标要区分“浏览器不支持”和“用户拒绝”,否则无法决定改文案还是关功能。

7. 回滚与兼容

用远程 flag 关闭新创建尝试,保留已有 passkey 的登录能力。撤回时不删除凭据,避免把发布回滚误做成账户破坏。服务端保留旧 challenge 版本的验证窗口,并设置过期时间;规范或浏览器行为改变后重新进行兼容测试。

高质量示范回答

我会把 conditional create 当作可撤回的增强路径。前端先检查浏览器能力,再由账号状态、最近认证强度和 feature flag 决定是否尝试;每个页面会话只允许一个请求,重复请求用 AbortController 取消。服务端为当前用户生成一次性 challenge,并校验 challenge、origin、RP ID、签名和 credential ID 后才保存。用户取消、不支持或超时都回到密码登录,不把失败当成登录失败。灰度按平台和风险分批,观察能力通过率、同意率、验证失败、重复凭据、回退率和恢复工单。关闭 flag 只停止新创建,保留已有 passkey 和撤销能力。

常见错误

  • 错误表现 → 只检查 PublicKeyCredential 是否存在 → 对象存在不代表 conditional create 和验证器都可用;修正方法:使用能力检测并保留回退路径。
  • 错误表现 → 页面加载就静默调用创建 → 用户未同意且容易产生重复提示;修正方法:在明确的高信任时机触发,并让用户控制继续。
  • 错误表现 → 只在前端判断成功 → challenge、origin 或账户归属可能未验证;修正方法:服务端完成完整注册验证。
  • 错误表现 → 回滚时删除已创建凭据 → 发布回退变成账户破坏;修正方法:关闭新创建 flag,凭据撤销独立处理。

追问及应对

用户拒绝创建后是否每天再提示?

不要无限提示。记录本地冷却期和服务端策略版本,只有账户风险、设备或产品条件显著变化时再询问;拒绝本身不应影响密码登录。

同一账户出现两个相同 credential ID 怎么办?

把 credential ID 设为唯一键,注册接口做幂等处理并记录来源。若数据库已有重复数据,先冻结新增写入,再按用户与 credential ID 合并或人工审核,不能静默覆盖。

浏览器支持能力但创建成功率突然下降,先查什么?

先按浏览器版本、平台、认证器类型和错误码切片,区分用户取消、超时、策略拒绝和服务端验证失败。暂停受影响分组的 flag,保留密码与已有 passkey 登录,修复后用小流量重新验证。

公开来源

同类题目