TOTP/OTP

RFC 6238 二步验证码 + 二维码

421 次访问
TOTP · TIME-BASED OTP · RFC 6238

TOTP 二步验证

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 接入双因子认证

远程办公员工通过 VPN 接入公司内网。输入 LDAP 密码后,再填入本工具显示的 TOTP 验证码。VPN 网关校验动态码通过后才分配内网 IP。相比硬件令牌(易丢失、需采购),本工具零成本、跨平台,员工用同一浏览器即可完成全部操作。

对比矩阵本工具 vs 竞品 vs 传统方法

维度本工具竞品 A (Google Authenticator)传统方法 (短信/邮件)
数据隐私纯浏览器,零上传本地存储,但依赖 Google 账号同步服务商存储,可能被拦截
处理速度即时生成即时生成1-30 秒延迟
离线可用完全离线完全离线需要网络信号
多设备同步无法同步支持云同步无同步,独立发送
费用免费免费按条计费 (0.05-0.5 元/条)
注册要求无需注册需 Google 账号需手机号
平台依赖任何浏览器仅 Android/iOS所有手机

使用指南

上手步骤 · 输入输出 · 避坑提示

输入输出示例7 个典型场景,覆盖常规、边界与易错

输入输出说明
JBSWY3DPEHPK3PXP123456典型场景:标准 16 位 Base32 密钥
otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example654321典型场景:粘贴完整 otpauth URL 自动解析
JBSWY3DPEHPK3PXP654321典型场景:同一密钥在不同时间输出不同码
JBSWY3DPEHPK3PXP123456边界 case:30 秒周期切换瞬间的验证码
GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ789012边界 case:32 位长密钥(SHA256 算法)
JBSWY3DPEHPK3PXP000000易错 case:时间不同步导致输出全零码
JBSWY3DPEHPK3PXP123456易错 case:用户误将密钥当成验证码输入

常见错误对照8 个常踩的坑 · 错误 → 修复

1. 密钥 Base32 编码包含非法字符

错误
JBSWY3DPEHPK3PXP
修复
JBSWY3DPEHPK3PXP

TOTP 密钥必须是 Base32 编码(字母 A-Z 和数字 2-7),不含 '1'、'8'、'9'、'0' 或小写字母。大小写不敏感,但建议全大写避免混淆。

2. 密钥长度不是 16/24/32 字符

错误
JBSWY3DPEHPK3P
修复
JBSWY3DPEHPK3PXP

RFC 6238 规定密钥长度应为 160 位(32 字符 Base32)或更长;16/24 字符也可用但安全性降低。长度不对会导致生成码与服务器不匹配。

3. 时间步长设置为非 30 秒

错误
period=60
修复
period=30

大多数 TOTP 实现(Google Authenticator、Authy)默认 30 秒步长。设为 60 秒会导致验证码有效期翻倍,但与其他客户端不兼容。

4. 使用 SHA-256 但服务端只支持 SHA-1

错误
algorithm=SHA256
修复
algorithm=SHA1

RFC 6238 默认使用 SHA-1;部分实现支持 SHA-256/SHA-512。若服务端未声明算法,必须用 SHA-1 否则验证码永远不匹配。

5. 6 位码但服务端要求 8 位

错误
digits=6
修复
digits=8

TOTP 支持 6 或 8 位数字。多数平台用 6 位,但某些银行或企业系统要求 8 位。位数不匹配会导致验证失败。

6. 时间戳未使用 Unix 时间(秒)

错误
time=1712345678000
修复
time=1712345678

TOTP 算法基于 Unix 时间戳(秒),而非毫秒。传入毫秒值会导致步长计算错误,生成完全不同的验证码。

7. 二维码内容缺少 issuer 参数

错误
otpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXP
修复
otpauth://totp/Example:user?secret=JBSWY3DPEHPK3PXP&issuer=Example

缺少 issuer 参数时,部分认证器(如 Google Authenticator)无法正确分组条目,导致多个账号显示为 'user@unknown' 难以区分。

8. 二维码内容中 issuer 和 label 不一致

错误
otpauth://totp/MyApp:user?secret=...&issuer=Example
修复
otpauth://totp/Example:user?secret=...&issuer=Example

RFC 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。

原理图

步骤 1输入密钥或扫描二维码步骤 2浏览器内计算 TOTP步骤 3显示 6 位验证码关键细节支持 Base32 / otpauth:// 格式密钥基于 RFC 6238,使用当前时间戳(30 秒步长)计算 HMAC-SHA1结果实时刷新,不依赖网络,数据仅在本地处理
用户输入 本地处理 输出结果

开发者集成

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 个高频疑问

这个在线 TOTP 生成器怎么用?需要安装什么吗?
不需要安装任何软件。打开页面后,在「密钥」输入框中粘贴你从网站(如 Google、GitHub)获得的 Base32 密钥(通常是一串大写字母和数字),然后点击「生成」按钮,工具就会立即显示当前 30 秒周期内的 6 位动态验证码。如果网站提供了二维码,也可以直接上传二维码图片,工具会自动解析密钥。生成的验证码可直接复制填入登录页面。
为什么生成的验证码和我手机上的 Authenticator 不一样?
验证码不一致通常是两个原因:1)密钥输入错误——检查是否漏了字母、大小写是否一致(Base32 编码通常用大写字母);2)设备时间不同步——TOTP 依赖当前时间的 30 秒窗口,手机和电脑时间差超过 30 秒就会生成不同码。本工具使用浏览器获取的系统时间,可以在操作系统中校准时间(如 Windows 自动同步 time.windows.com),或者对比手机和电脑的秒数是否一致。
这个工具生成的验证码有效期是多久?
每个验证码的有效期是 30 秒,这是 TOTP(RFC 6238)标准定义的默认时间步长。每 30 秒自动更新一次,页面上的倒计时进度条会显示当前码还剩多少秒。如果验证码刚刷新就倒计时结束,实际在服务端(如 Google 服务器)的窗口会有 ±30 秒的容差,所以只要在 30 秒内输入通常都能通过。但建议在倒计时剩余 5 秒前使用,避免因网络延迟导致超时。
工具会保存我的密钥或验证码吗?安全吗?
完全不会保存。本工具是纯前端实现(FE),所有计算都在你的浏览器中通过 JavaScript 完成,密钥和生成的验证码不会离开你的设备。可以打开浏览器开发者工具的网络(Network)面板验证:输入密钥后没有任何网络请求发出。关闭页面或刷新后,密钥自动清除。如果需要更安全的环境,可以复制页面代码到本地 HTML 文件,断网后使用。
这个工具和 Authy / Google Authenticator 有什么区别?
核心算法完全一致(都是 RFC 6238),所以同一密钥会生成相同的验证码。区别在于:1)本工具无需安装,打开浏览器即可使用,适合临时或快速场景;2)不保存密钥和账户列表,每次需手动输入密钥或上传二维码,不适合管理多个账户;3)无法离线使用(需要浏览器加载页面);4)没有云同步或备份功能。建议将本工具作为手机验证器的备用方案,或用于调试和测试密钥是否有效。
我的密钥是 16 位数字和字母,但工具提示密钥格式不对怎么办?
TOTP 标准要求密钥必须是 Base32 编码,通常包含大写字母 A-Z 和数字 2-7,长度一般是 16、24 或 32 个字符。常见错误:1)密钥里包含小写字母——请全部转为大写;2)密钥里包含数字 1 或 8——Base32 不使用 1、8、9、0,请检查来源是否为正确密钥;3)密钥是明文密码而非 Base32——很多网站(如 Steam 令牌)提供的是明文密钥,需要先使用 Base32 编码工具转换。如果不确定,可以重新从网站获取密钥。
上传二维码图片后提示无法解析,怎么办?
二维码无法解析通常有三个原因:1)图片太模糊或尺寸太小——建议上传 300×300 像素以上的清晰截图,避免翻拍屏幕产生的摩尔纹;2)二维码内容不包含 TOTP 密钥——有些二维码是登录链接或纯文本,不包含 `otpauth://` 格式的 URI;3)图片格式不支持——建议使用 PNG 或 JPG 格式,部分浏览器对 WebP 的支持有限。可以尝试先用手机扫码确认二维码内容是否包含 `secret=` 参数。
生成的验证码是 8 位数字,但我需要的网站只接受 6 位,怎么回事?
TOTP 标准(RFC 6238)允许不同的验证码长度,常见的有 6 位和 8 位两种。本工具默认输出 6 位数字,如果看到 8 位,可能是因为你使用的密钥对应的网站(如某些银行或企业系统)配置了 8 位输出。可以在工具界面上查找「位数」或「Digits」选项,手动调整为 6 位。如果工具没有此选项,说明当前版本固定为 6 位输出,生成的 8 位码可能是其他工具或扩展导致的显示问题。
选择 打开 +新窗口 esc关闭