一、2fa是啥
2FA 不是一个算法,是一种"双因素验证"的统称。
你在 GitHub、Google、微软、AWS、Discord 等用的那个 6 位动态码,
99% 都是同一个通用标准算法:TOTP(RFC 6238)
- 真正通用的算法:TOTP
TOTP = Time-Based One-Time Password
基于时间的一次性密码
它的特点:
- 6 位数字
- 每 30 秒 刷新一次
- 只需要一个 Base32 密钥
- 所有平台通用:GitHub / Google / 微软 / 阿里云 / 腾讯云 / Discord / 几乎所有国外网站
就是标准 TOTP,
可以通用支持所有支持 2FA 的网站。
- 哪些网站能用你手里这个网页版?
全部能用:
- GitHub ✅
- Google 账号 ✅
- Microsoft 账号 ✅
- Discord ✅
- AWS / Azure / GCP ✅
- 阿里云、腾讯云、华为云 ✅
- 大部分支持"验证器 App"的网站 ✅
只要它让你:
- 给你一个 密钥(Base32)
- 或者让你扫 二维码
那它 100% 就是 TOTP,你的工具就能用。
- 不通用的情况(极少)
只有两种不通用:
- 短信验证码(不是算法,是短信)
- WebAuthn / 硬件密钥(YubiKey 那种)
- 某些银行/国内平台自己搞的私有加密算法
但正常互联网产品 2FA = 全通用 TOTP。
- 总结
2FA 是功能名字,TOTP 是通用算法。
GitHub 2FA = 标准 TOTP,你的工具通用所有支持 2FA 的网站。
再给大家做一个2fa.html通用网页版:
通用 TOTP 管理器(支持多账号、本地保存、加密、扫码),完全通用所有网站代码如下:阿弥陀佛
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>GitHub 2FA 验证器</title>
<style>
*{box-sizing:border-box;font-family:system-ui, sans-serif}
body{background:#121212;color:#fff;padding:20px;max-width:400px;margin:0 auto}
.box{background:#1e1e1e;padding:24px;border-radius:16px;margin-top:30px}
h2{text-align:center;margin:0 0 16px;font-size:20px}
input{width:100%;padding:12px;border-radius:8px;border:none;background:#2a2a2a;color:#fff;font-size:16px;margin-bottom:12px}
#code{font-size:48px;letter-spacing:6px;text-align:center;color:#4cd964;margin:20px 0}
#time{text-align:center;color:#999;font-size:14px}
</style>
</head>
<body>
<div class="box">
<h2>GitHub 2FA 验证器</h2>
<input id="key" placeholder="输入 2FA Base32 密钥" autocomplete="off">
<div id="code">------</div>
<div id="time">30 秒后刷新</div>
</div>
<script>
const base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
function base32ToBuffer(base32) {
base32 = base32.toUpperCase().replace(/=+$/, "");
let bits = "";
for (let c of base32) {
let val = base32Chars.indexOf(c);
if (val < 0) throw new Error("无效密钥");
bits += val.toString(2).padStart(5, "0");
}
const bytes = new Uint8Array(Math.floor(bits.length / 8));
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(bits.slice(i * 8, i * 8 + 8), 2);
}
return bytes;
}
async function hmacSha1(key, data) {
const cryptoKey = await crypto.subtle.importKey(
"raw", key, { name: "HMAC", hash: "SHA-1" }, false, ["sign"]
);
return new Uint8Array(await crypto.subtle.sign("HMAC", cryptoKey, data));
}
function counterBuffer() {
const c = Math.floor(Date.now() / 1000 / 30);
const b = new ArrayBuffer(8);
const v = new DataView(b);
v.setUint32(4, c);
return new Uint8Array(b);
}
async function totp(secret) {
try {
const key = base32ToBuffer(secret);
const hash = await hmacSha1(key, counterBuffer());
const offset = hash[hash.length - 1] & 0xf;
const code = ((hash[offset] & 0x7f) << 24) |
((hash[offset+1] & 0xff) << 16) |
((hash[offset+2] & 0xff) << 8) |
(hash[offset+3] & 0xff);
return (code % 1000000).toString().padStart(6, "0");
} catch (e) {
return "------";
}
}
function remain() {
return 30 - (Math.floor(Date.now() / 1000) % 30);
}
let timer;
async function update() {
const secret = document.getElementById("key").value.trim();
const code = await totp(secret);
document.getElementById("code").innerText = code;
document.getElementById("time").innerText = remain() + " 秒刷新";
}
function start() {
clearInterval(timer);
update();
timer = setInterval(update, 1000);
}
document.getElementById("key").addEventListener("input", start);
start();
</script>
</body>
</html>
二、如何实现专人专用
这个 6 位动态验证码,怎么做到「专人专用、别人拿不走」。
核心一句话
专人专用 = 密钥只存在你一个人的设备里,绝不外传、绝不上传。
真正能做到的实现原理,不玩虚的。
一)、它是怎么保证「专人专用」的?
整个系统只有两个东西:
- 密钥(Secret)
一串 Base32 乱码,只在你开启 2FA 时出现一次。
作用 = 身份唯一凭证。 - 时间(当前时间)
全世界统一,服务器和你手机时间一致。
生成验证码的公式:
验证码 = HMAC-SHA1(密钥, 时间片)
也就是说:
只有同时拥有「密钥 + 当前时间」,才能算出正确 6 位码。
二)、怎么做到「别人算不出来」?
- 黑客不知道你的密钥 → 就算知道时间也没用
- 密钥不联网、不传服务器、不被截获
- 验证码30 秒过期,截获也没用
这就是数学上的安全。
三)、你要怎么配置,才能真正「专人专用」?
我给你最安全、最标准的 4 步:
- 密钥只存你自己的设备
- 不发给任何人
- 不存聊天记录
- 不存云端(除非加密)
- 只放在你的:
- 手机验证器(Authy / Google Authenticator)
- 你自己写的本地网页
- 本地密码管理器(Bitwarden、1Password)
→ 密钥在哪,谁就能登录。
- 开启 2FA 时,只扫你自己的屏幕
不要让别人帮你开,不要远程截图。
二维码 = 密钥的另一种形式。
- 设备锁屏 + 密码
别人拿到你手机,解不开锁 = 拿不到密钥。
- 备份恢复码(最重要)
开启 2FA 时,GitHub 会给你 10 串恢复码。
- 保存在安全地方
- 不联网
- 不丢
- 手机坏了也能恢复账号
四)、最安全的「专人专用」结构(你可以直接照做)
plaintext
你本人
↓
你的手机/电脑(只有这里有密钥)
↓
生成 6 位码
↓
登录 GitHub
别人没有密钥 → 永远无法生成正确验证码。
五)、最通俗比喻
- 密钥 = 你的指纹
- 时间 = 现在的时刻
- 6 位码 = 你此刻的临时通行证
只有你有指纹,只有你能生成此刻的通行证。
六)、结论
只要密钥不泄露、只存在你自己设备里,
这个验证码就是 100% 专人专用,无法仿冒、无法共享。
三、github恢复码核心作用
github-recovery-codes.txt(GitHub 恢复码)** 是你开启 GitHub 双因素认证(2FA)后,用于紧急找回账号的一次性备用验证码。
一)、核心作用
- 当你丢失手机、无法使用 Authenticator 应用、收不到短信等,无法获取 2FA 动态码时,用恢复码可直接登录并重置 2FA。
- 每个恢复码只能用一次,用完即失效。
- 一套恢复码通常有 16 个 ,默认文件名:
github-recovery-codes.txt。
二)、如何获取/下载恢复码
- 登录 GitHub → 右上角头像 → Settings(设置)。
- 左侧菜单:Password and authentication(密码与认证)。
- 找到 Recovery codes → 点击 View / Download。
- 选择:Download(保存到本地)、Print(打印)、Copy(复制到密码管理器)。
- 务必离线安全保存(密码管理器、加密文件、纸质备份),不要存在云端或与账号同设备。
三)、如何使用恢复码登录
- 正常输入 GitHub 用户名 + 密码 → 点击 Sign in。
- 在 2FA 验证页,点击下方:Use a recovery code(使用恢复码)。
- 输入任意一个未使用过的恢复码 → 点击 Verify。
- 登录成功后,立即生成新的一套恢复码(旧码全部失效)。
四)、常见问题与注意事项
- 提示"Recovery code invalid":
- 确认未输错、未重复使用 、无空格/大小写(通常不区分大小写)。
- 换一个未用过的恢复码重试。
- 生成新恢复码:
- 登录后进入 Password and authentication → Recovery codes → Generate new codes。
- 生成后旧码立即全部作废,务必重新保存。
- 丢失所有恢复码:
- 只能走 GitHub 账号人工申诉流程,耗时较长。