你打开 VPN 客户端,输入密码,认证器里的六位数字却被判为无效——两次,第三次也一样。账户从昨天起没有任何变化,于是第一反应是删掉认证器里的条目重新扫描,这通常是错误的修复。一次性验证码不是第二个密码:网关必须在特定步骤、从特定已注册条目、在特定时间窗内索取它,而大多数拒绝都发生在比较数字之前。在动注册之前,先弄清你处在哪一步。

提示顺序决定你在哪条流程里

几乎所有的带码 VPN 登录都落在三种形态里。两步形态下,客户端发送密码,服务器发出挑战,客户端再次询问。合并形态下,网关要求密码和码在同一次提交中给出,有时直接拼接,有时放在只有运维才有文档的分隔符之后。浏览器形态下,客户端根本没有输入框:码填进网页,或者由推送批准替代,桌面客户端只等结果。

形态错了会像码错一样。把新码粘贴进只接受密码的输入框,服务器会把它读成密码的一部分。客户端一侧,OpenVPN 2.4 及以后版本让差别变得可见:用 AUTH_FAILED,CRV1: 应答的服务器期待挑战应答,因此配置文件需要 static-challenge 或 SCRV1: 形式的密码文件。只带 auth-user-pass 的旧配置会先验证密码然后卡住,日志里看起来像 OTP 失败,但实际上根本没有发出验证码。

WireGuard 值得作为例外单列:它认证的是密钥对而不是人,所以没有输入验证码的地方。如果服务商宣传有码,那是隧道之外的某个东西在接受它。

服务器拿这六位数字做什么

基于时间的验证码遵循 RFC 6238,它包装了 RFC 4226 中更早的计数器结构:对一个移动因子做 HMAC,默认截成六位。TOTP 的移动因子是当前 Unix 时间除以一个步长,除非运维改过,否则是 30 秒。校验方从不把你的数字和存储值比较;它用共享种子重新算出期望的码,并且通常也接受相邻步长,所以一次较慢的往返不会让登录失败。

有两个后果常被忽略。手机的时区无关紧要,因为种子从不看本地时钟——只有与真实 UTC 的偏差才重要,而快了两分钟的设备会在每个码上失败,同时显示着干净的倒计时。验证码在设计上是一次性的:校验方会记住该种子最后接受过的计数器值,所以同样的数字再次提交,即使在同一时间窗内也会被拒绝。超时后重试的客户端可能把它刚发出的码烧掉。

计数器型令牌每次按下都会推进计数器,所以如果码生成后从未提交就会失步;常见的修复是一个接受向前若干值的重同步窗口。如果运维注册的是 HOTP 而你的应用显示 TOTP,每个值都会以看起来像时钟问题的方式出错。二维码背后的配置 URI 会写明类型、位数、周期和哈希。

看起来像码错的故障

最常见的原因是已注册条目。认证器应用按签发方和账户给条目打标签,所以在同一个 VPN 上有两个身份的人可能有两个标签只差一个字符的条目。码只对生成它的那个种子有效,对其他任何东西都无效。把手机上的标签与服务器记录的用户名对比,而不是与你记得自己输入的内容对比。

第二是不匹配的参数集。用八位、60 秒周期或 SHA-256 注册的种子会产生期望六位、30 秒和 SHA-1 的校验方拒绝的码,而在客户端这和一个错误的码无法区分。它出现在把条目从二维码照片重新加入、或用默认值重建令牌记录的迁移之后。

第三与码无关。网关通常对密码错误、验证码过期和账户被禁用返回同一条通用认证失败,这是有意为之,让人无法探测究竟是哪个因素失败。要读网关或 RADIUS 日志,而不是客户端的提示条:从未发出的挑战、没有 OTP 属性的访问拒绝和策略拒绝在屏幕上看起来一样,却导向不同的下一步。

缩小范围的一小段顺序

从最便宜的检查开始,在第一个不成立的步骤停下。

  1. 等一个新码,只提交一次,记下挑战是在密码被接受之前还是之后出现。
  2. 把认证器里的标签与服务器保存的用户名对上。
  3. 确认配置到底能不能应答挑战,就像上面 CRV1 的情形。
  4. 把设备时钟与已知时间源对比;超过几十秒的偏差本身就会让 TOTP 失败。
  5. 问运维令牌是 TOTP 还是 HOTP,注册的是哪位、什么周期和什么哈希。

两条规则可以避免事情变糟。不要反复重试:许多网关按账户统计失败次数,要么锁定账户,要么开始延迟响应,一波尝试会把小配置错误变成一张支持工单。也不要把重新注册令牌当作诊断,因为那会让旧种子失效;如果真正的故障是客户端从未发出的挑战,你手上就从一处改动变成了两处改动要解释。

把种子和恢复码留在循环之外

六位数字和它们背后的秘密不能互换。配置二维码或 Base32 种子会生成该账户今后所有验证码,所以它和密码属于同一类:不要出现在截图里,不要出现在工单评论里,也不要出现在先来联系你的人发起的聊天里。恢复码是另一套机制——一次性,往往完全跳过验证码提示,拿一个去测试账户就会移除你以后可能需要的备用路径。

有码也不代表登录页可信:相似域名上的 OTP 提示会收走一个有效码并在时间窗内重放,而证书仍然是告诉你正在哪里输入的东西。

如果顺序停在无法应答挑战的配置上,修好配置并用一个新码重测。如果停在不匹配的注册参数上,让运维先读令牌记录再让任何人扫码。如果停在锁定上,等它过去,而不是换客户端——真正的障碍是账户状态,不是应用。

相关文章