2FA 验证码是怎么生成的?TOTP 详解
作者:Novaz 团队 · 更新于 2026年10月29日
Novaz 操作步骤已在 1.0.5 版本中核实
本文译自英文指南。在服务的网站上,按钮和菜单的中文名称可能略有不同。
本页内容
身份验证器 App 和网站各自用双方都有的两样东西算出同一个 6 位数:一个双方曾经共享过的密钥,以及当前时间。登录时,两者之间不传送任何数据。正因如此,没有信号时验证码也能用,而且每 30 秒变化一次。这种方法叫 TOTP,即基于时间的一次性密码(time-based one-time password),是一项开放标准(RFC 6238)。
要素 1:设置密钥
开启 2FA 时,网站会生成一个随机密钥,以二维码的形式显示给你,同时附上一个文本版本,叫作设置密钥。你的 App 会把它保存下来。从此以后,网站和你的 App 拥有同一个密钥,而其他任何人都不应该有。
二维码其实只是一个标准格式的链接 otpauth://totp/…,里面包含密钥、服务名称、你的账号名称,以及下文介绍的可选设置。我们的 2FA 二维码解码器可以显示二维码里的内容。
要素 2:按步长计数的时间
双方都把当前时间换算成自 1970 年 1 月 1 日起经过的秒数(Unix 时间),再除以 30 并舍去余数。结果是一个每 30 秒加一的整数。RFC 6238 把它称为 T,并推荐 “a default time-step size of 30 seconds”(默认时间步长为 30 秒)。
把两者合成验证码
App 把密钥和 T 一起送入 HMAC(一种密码学函数),通常使用 SHA-1。然后用 HOTP 标准(RFC 4226,第 5.3 节)定义的方法把结果截短成一个短数字:
- HMAC 结果的最后 4 位(bit)指定其中的一个位置。
- App 从该位置取出 31 位(bit),作为一个数字。
- 保留这个数字的最后 6 位数字。有些服务使用 8 位。
只要密钥或时间步长变了,得到的验证码就完全不同。从验证码无法反推出密钥。
Try it: a live TOTP code
Calculated in your browser from an example key. Don't paste a real setup key here.
Current code
…
Previous: …
Next: …
- Unix time
- …
- Time step T = ⌊time ÷ 30⌋
- …
- Seconds left
- …
网站为什么会接受它
网站用它保存的那份密钥和自己的时钟做同样的计算。如果数字一致,你就能登录。实际使用中,有两个细节让这一机制行得通:
- 给延迟留一点余地。 你在一个步长末尾输入的验证码,可能在下一个步长才送达。RFC 6238 建议 “at most one time step is allowed as the network delay”(最多允许一个时间步长作为网络延迟),所以许多网站也接受当前验证码的前一个。
- 每个验证码只能用一次。 标准规定,对于已经接受过的验证码,服务器 “MUST NOT accept the second attempt”(不得接受第二次尝试)。美国 NIST 的指南也是这样规定的:验证方 “SHALL accept a given OTP only once while it is valid”(在一次性密码有效期内只能接受它一次)(NIST SP 800-63B-4)。
这也是时钟不准会导致验证码失效的原因。如果你的 iPhone 偏差了一分钟,它算出的就是与网站不同的时间步长的验证码。参见身份验证器验证码无效?
服务可以更改的设置
标准允许一定的变化,二维码可以把这些设置带过来:
| 设置 | 常用值 | 也允许 |
|---|---|---|
| 哈希算法 | SHA-1 | SHA-256、SHA-512(RFC 6238,第 1.2 节) |
| 位数 | 6 | 7 或 8(RFC 4226,第 5.3 节) |
| 间隔 | 30 秒 | 其他时长 |
如果某项服务使用了不常见的设置,请扫描二维码添加,而不是手动输入密钥,这样 App 也能获得这些设置。
TOTP 与 HOTP
HOTP 是较早的标准,它使用一个每次请求验证码时加一的计数器,而不是时间。TOTP 就是以时间步长为计数器的 HOTP:“TOTP = HOTP(K, T)”。如今大多数网站都使用 TOTP。
TOTP 防不住什么
因为验证码要由你自己输入,一个足以乱真的假登录页面可以向你索要验证码并立即使用。NIST 说得很明白:“OTP authentication is not phishing-resistant”(一次性密码认证不能抵御网络钓鱼)。通行密钥和安全密钥则可以。详见身份验证器 App 与短信验证码。
在 Authenticator App - Novaz 中
Novaz 在你的 iPhone 上生成标准的 TOTP 验证码:
- 通过二维码添加: SHA-1、SHA-256 或 SHA-512;6 到 8 位;间隔 1 到 300 秒。
- 手动输入密钥添加: 一律 6 位、30 秒和 SHA-1。
它不生成 HOTP 验证码。它还会检查 iPhone 的时钟,在偏差达到 15 秒或更多时提醒你。