正在加载,请稍候…

OTP / TOTP 详解:双因素认证的工作原理

了解基于时间的一次性密码(TOTP)如何工作。生成和验证用于双因素认证系统的 OTP 代码。

OTP / TOTP 详解:双因素认证的工作原理

什么是双因素认证(2FA)?

双因素认证(2FA) 在密码之外增加了第二层验证。即使攻击者窃取了你的密码,如果没有第二因素,他们也无法登录。三种认证因素类别如下:

  • 你知道的信息 — 密码、PIN、安全问题
  • 你拥有的物品 — 手机、硬件令牌、智能卡
  • 你的生物特征 — 指纹、面部识别、声音

大多数 2FA 实现将密码(你知道的信息)与来自移动应用的一次性代码(你拥有的物品)结合使用。

OTP / TOTP 详解:双因素认证的工作原理 插图

TOTP 的工作原理

TOTP(基于时间的一次性密码)在 RFC 6238 中定义。它生成一个每 30 秒变化一次的 6 位数字代码,在应用和服务器之间无需任何网络通信即可同步。

设置过程:

  1. 服务器生成一个随机的密钥(通常为 20 字节 / 160 位)。
  2. 服务器将密钥显示为二维码。
  3. 用户使用身份验证器应用(Google Authenticator、Authy 等)扫描二维码。
  4. 服务器和应用现在共享相同的密钥。

代码生成:

counter = floor(currentUnixTime / 30)
HOTP = HMAC-SHA1(secret, counter)
TOTP = HOTP truncated to 6 digits

由于双方都根据相同的计数器(当前时间 ÷ 30)和相同的密钥计算 TOTP,因此它们总是得到相同的 6 位代码——无需网络。

验证:

服务器检查提交的代码是否与当前 TOTP 匹配,通常还会检查前一个和下一个(以考虑时钟偏差和网络延迟)。有效代码被接受一次,然后失效以防止重放攻击。

OTP / TOTP 详解:双因素认证的工作原理 插图

HOTP:基于计数器的前身

HOTP(基于 HMAC 的一次性密码,RFC 4226)使用递增计数器而非时间。每次生成代码时计数器递增。

  • 优点: 无需时钟同步,适用于硬件令牌。
  • 缺点: 如果生成了代码但未使用,计数器可能不同步。

TOTP 通常更受软件身份验证器的青睐。

身份验证器应用

应用 开源 多设备 备份
Google Authenticator iOS + Android 云备份选项
Authy 加密云备份
Microsoft Authenticator 云备份
Aegis Android 加密文件备份
Raivo iOS iCloud 备份

为了最大安全性,推荐使用 Aegis(Android)和 Raivo(iOS)——两者都是开源的,并支持加密的本地/云备份。

TOTP 安全特性

抗钓鱼

TOTP 代码仅在 30 秒内有效。如果用户被诱骗在钓鱼网站上输入代码,攻击者必须在代码过期前使用它——而且只能使用一次。

OTP / TOTP 详解:双因素认证的工作原理 插图

防重放

由于每个代码都有时间限制且一次性使用,重放截获的代码将无效。

抗暴力破解

在 10^6 种可能的 6 位代码和 30 秒有效期内,攻击者在窗口过期前每秒只能检查 3 个代码。锁定策略进一步限制了尝试次数。

TOTP 的局限性

  • SIM 卡交换 — 基于短信的 2FA 易受攻击;TOTP(基于应用)则不受影响。
  • 实时钓鱼 — 高级攻击实时代理凭据,绕过 TOTP。硬件密钥(FIDO2/WebAuthn)可防止此类攻击。
  • 设备丢失 — 丢失手机且没有备份代码会导致无法登录。请始终保存备份代码。
  • 账户恢复 — 许多服务的账户恢复机制薄弱,完全绕过 2FA。

在应用中实现 TOTP

// 使用 'otplib' (npm)
import { authenticator } from 'otplib';

// 生成密钥(仅在用户设置时执行一次)
const secret = authenticator.generateSecret();

// 生成当前 TOTP
const token = authenticator.generate(secret);

// 验证用户提交的令牌
const isValid = authenticator.verify({ token, secret });
# 使用 'pyotp' (pip)
import pyotp

secret = pyotp.random_base32()
totp = pyotp.TOTP(secret)
token = totp.now()           # 当前代码
totp.verify(token)           # 返回 True

使用此工具

此 OTP 生成器接受 TOTP 密钥(Base32 编码),并显示当前代码以及倒计时器。你还可以根据密钥验证代码——这对于测试你的 TOTP 实现非常有用。

→ 尝试 OTP 生成器