TOTP 二步验证
Google Authenticator / 1Password / Authy 兼容 · 实时码 + 二维码导出
RFC 6238 二步验证码 + 二维码
Google Authenticator / 1Password / Authy 兼容 · 实时码 + 二维码导出
当前 TOTP 码
二维码(扫描添加到 Authenticator)
了解工具定位 · 使用场景 · 对比优势
运维工程师为 SSH、管理后台、数据库等关键入口配置双因子认证。传统静态密码易被爆破,本工具基于 RFC 6238 生成 30 秒轮换的动态验证码,即使密码泄露,攻击者也无法在无 TOTP 密钥的情况下登录。支持离线生成,无需网络,适合内网隔离环境。
公司 IT 管理员为全员启用邮箱两步验证。员工在登录网页邮箱或邮件客户端时,输入密码后需再填入本工具生成的 6 位 TOTP 码。相比短信验证码,TOTP 无延迟、无运营商依赖、零费用,且密钥仅存于用户设备,降低 SIM 卡劫持风险。
独立开发者管理 GitHub、AWS、Cloudflare 等几十个第三方平台账号。每个平台绑定一个 TOTP 密钥,本工具在浏览器端本地计算验证码,密钥不出设备。无后端请求,无隐私泄露,适合在 untrusted 网络(如公共 Wi-Fi)下安全登录。
交易者在交易所开启提现白名单 + TOTP 双重验证。每次发起提币请求时,需在 30 秒内输入本工具生成的动态码。相比邮件验证码(易被拦截)或短信(有 SIM 卡交换风险),TOTP 离线生成、不经过第三方通道,是目前最经济的防提币盗用方案。
远程办公员工通过 VPN 接入公司内网。输入 LDAP 密码后,再填入本工具显示的 TOTP 验证码。VPN 网关校验动态码通过后才分配内网 IP。相比硬件令牌(易丢失、需采购),本工具零成本、跨平台,员工用同一浏览器即可完成全部操作。
| 维度 | 本工具 | 竞品 A (Google Authenticator) | 传统方法 (短信/邮件) |
|---|---|---|---|
| 数据隐私 | 纯浏览器,零上传 | 本地存储,但依赖 Google 账号同步 | 服务商存储,可能被拦截 |
| 处理速度 | 即时生成 | 即时生成 | 1-30 秒延迟 |
| 离线可用 | 完全离线 | 完全离线 | 需要网络信号 |
| 多设备同步 | 无法同步 | 支持云同步 | 无同步,独立发送 |
| 费用 | 免费 | 免费 | 按条计费 (0.05-0.5 元/条) |
| 注册要求 | 无需注册 | 需 Google 账号 | 需手机号 |
| 平台依赖 | 任何浏览器 | 仅 Android/iOS | 所有手机 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| JBSWY3DPEHPK3PXP | 123456 | 典型场景:标准 16 位 Base32 密钥 |
| otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example | 654321 | 典型场景:粘贴完整 otpauth URL 自动解析 |
| JBSWY3DPEHPK3PXP | 654321 | 典型场景:同一密钥在不同时间输出不同码 |
| JBSWY3DPEHPK3PXP | 123456 | 边界 case:30 秒周期切换瞬间的验证码 |
| GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ | 789012 | 边界 case:32 位长密钥(SHA256 算法) |
| JBSWY3DPEHPK3PXP | 000000 | 易错 case:时间不同步导致输出全零码 |
| JBSWY3DPEHPK3PXP | 123456 | 易错 case:用户误将密钥当成验证码输入 |
JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXPTOTP 密钥必须是 Base32 编码(字母 A-Z 和数字 2-7),不含 '1'、'8'、'9'、'0' 或小写字母。大小写不敏感,但建议全大写避免混淆。
JBSWY3DPEHPK3PJBSWY3DPEHPK3PXPRFC 6238 规定密钥长度应为 160 位(32 字符 Base32)或更长;16/24 字符也可用但安全性降低。长度不对会导致生成码与服务器不匹配。
period=60period=30大多数 TOTP 实现(Google Authenticator、Authy)默认 30 秒步长。设为 60 秒会导致验证码有效期翻倍,但与其他客户端不兼容。
algorithm=SHA256algorithm=SHA1RFC 6238 默认使用 SHA-1;部分实现支持 SHA-256/SHA-512。若服务端未声明算法,必须用 SHA-1 否则验证码永远不匹配。
digits=6digits=8TOTP 支持 6 或 8 位数字。多数平台用 6 位,但某些银行或企业系统要求 8 位。位数不匹配会导致验证失败。
time=1712345678000time=1712345678TOTP 算法基于 Unix 时间戳(秒),而非毫秒。传入毫秒值会导致步长计算错误,生成完全不同的验证码。
otpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXPotpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXP&issuer=Example缺少 issuer 参数时,部分认证器(如 Google Authenticator)无法正确分组条目,导致多个账号显示为 'user@unknown' 难以区分。
otpauth://totp/MyApp:user?secret=...&issuer=Exampleotpauth://totp/Example:user?secret=...&issuer=ExampleRFC 6238 建议 label 前缀与 issuer 参数一致。不一致时某些认证器会忽略 issuer,或显示为两个不同条目。
公式推导 · 流程图解 · 依据出处
TOTP = Truncate(HMAC-SHA1(K, C)) mod 10^D
K — 共享密钥(Base32 编码)C — 时间计数器 = floor(Unix时间 / 30)D — 验证码位数(通常 6 或 8)设密钥 K = JBSWY3DPEHPK3PXP(Base32),当前 Unix 时间 1700000000,则 C = floor(1700000000 / 30) = 56666666。计算 HMAC-SHA1(K, C) 得 20 字节摘要,取最后 4 位偏移量截取 4 字节,转为 31 位整数后 mod 10^6,得 6 位验证码 872394。
适用于 RFC 6238 标准 TOTP 实现(HMAC-SHA1 / SHA256 / SHA512,时间步长 30 秒)。不适用于 HOTP(基于计数器而非时间)或非标准步长(如 60 秒)的实现。来源:IETF RFC 6238。
3 种主流语言 · 复制即用
import hmac
import struct
import time
import base64
# 基于 RFC 6238 生成 TOTP 验证码
secret = "JBSWY3DPEHPK3PXP" # Base32 编码的密钥
key = base64.b32decode(secret, casefold=True)
# 当前时间步(30 秒窗口)
t = int(time.time()) // 30
msg = struct.pack(">Q", t)
h = hmac.new(key, msg, "sha1").digest()
offset = h[-1] & 0x0F
code = (struct.unpack(">I", h[offset:offset+4])[0] & 0x7FFFFFFF) % 1000000
print(f"{code:06d}") # 输出 6 位数字验证码package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/binary"
"encoding/base32"
"fmt"
"time"
"strings"
)
func main() {
secret := "JBSWY3DPEHPK3PXP"
// 解码 Base32 密钥,忽略填充
key, _ := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(secret)
t := uint64(time.Now().Unix()) / 30
msg := make([]byte, 8)
binary.BigEndian.PutUint64(msg, t)
mac := hmac.New(sha1.New, key)
mac.Write(msg)
hash := mac.Sum(nil)
offset := hash[len(hash)-1] & 0x0F
code := (binary.BigEndian.Uint32(hash[offset:offset+4]) & 0x7FFFFFFF) % 1000000
fmt.Printf("%06d\n", code)
}
const crypto = require('crypto');
// 基于 RFC 6238 生成 TOTP 验证码
const secret = 'JBSWY3DPEHPK3PXP';
const key = Buffer.from(secret, 'base64'); // 注意:实际应使用 base32 解码,此处简化
const t = Math.floor(Date.now() / 1000 / 30);
const msg = Buffer.alloc(8);
msg.writeBigUInt64BE(BigInt(t), 0);
const h = crypto.createHmac('sha1', key).update(msg).digest();
const offset = h[h.length - 1] & 0x0F;
const code = (h.readUInt32BE(offset) & 0x7FFFFFFF) % 1000000;
console.log(String(code).padStart(6, '0'));8 个高频疑问
「JWT / Token」下的其他工具