了解2FA(双因素认证)

1086 字
5 分钟
了解2FA(双因素认证)

越来越多项目要求启用2FA,不得不去了解它!


概念#

  1. 2FA 即:双因素认证 <=> Two-factor authentication <=> 2FA
  2. 双因素认证就是指,通过认证同时需要两个因素的证据,例如银行卡就是最常见的双因素认证,我们必须同时提供“银行卡”、“密码”两种信息才能拿钱

2FA的核心是组合2种不同类型的验证因子,验证因子主要分为以下3类:

  • 你知道的东西:密码、PIN码等
  • 你拥有的东西:手机、电脑安全密钥等,通过获取一次性验证码(OTP)或确认推送通知来完成验证
  • 你是什么:指纹、虹膜等

2FA 方案#

在实际应用中,最常用的 2FA 方案是 “密码 + 你拥有的东西”,因为生物特征(第三因素)需要特殊硬件支持,普适性稍差

方案(一)密码 + 硬件令牌#

例如银行的U盾、以前网络游戏(如DNF)的密保卡、登录GitHub或系统用的YubiKey。用户插入设备或输入设备上动态码后,再输入密码

方案(二)密码 + 手机短信验证码#

国内最常见的方案。登录时向绑定手机发送一条包含短时验证码的短信。注意:此方案安全性相对较低,因为短信可能被拦截、SIM卡可能被克隆,但胜在便捷

方案(三)密码 + 基于时间的一次性密码(TOTP)(当前主流且推荐的方案)#

这是公认较可靠的软件层面2FA方案,国际标准为RFC6238 。用户需要先在自己的手机上安装一个身份验证器App(如 Google Authenticator、Microsoft Authenticator、Authy 等)

  • 第一步(绑定):服务端生成一个密钥,以二维码形式展示给用户。
  • 第二步(保存):用户用App扫描二维码,密钥安全保存到手机(也就说这个密钥在手机和服务端上都存有了)。注意,密钥必须跟手机绑定。一旦用户更换手机,就必须生成全新的密钥
  • 第三步(验证):登录时,App使用密钥和当前时间戳,通过特定算法(如HMAC-SHA1)生成一个30秒或60秒(默认30秒)内有效的6-8位动态验证码。用户在有效期内,把这个动态验证码提交给服务器。服务器也使用密钥和当前时间戳,生成一个动态验证码,跟用户提交的验证码比对。只要两者不一致,就拒绝登录

TOTP的算法#

TOTP 的全称是”基于时间的一次性密码”(Time-based One-time Password),仔细看上面的步骤,我会有一个问题:App和服务端,如何保证30秒期间都得到同一个验证码?答案就是下面的这个公式:

Terminal window
TC = floor((unixtime(now) unixtime(T0)) / TS)
  • TC —> 时间计数器
  • unixtime(now) —> 当前 Unix 时间戳
  • unixtime(T0) —> 约定的起始时间点的时间戳,默认是0,也就是1970年1月1日
  • TS —> 哈希有效期的时间长度,默认是30秒

因此,上面的公式就变成下面的形式

Terminal window
TC = floor(unixtime(now) / 30)

所以,只要在 30 秒以内,TC 的值都是一样的。前提是服务端和手机端的时间必须同步。接下来,就可以算出验证码了。

Terminal window
TOTP = HASH(SecretKey, TC)

上面代码中,HASH就是约定的哈希函数,默认是 SHA-1

另外,TOTP 有“硬件生成器”和“软件生成器”之分,都是采用上面的算法

(左:硬件生成器,右:软件生成器)

TOTP硬件和软件生成器
TOTP硬件和软件生成器

TOTP的实现(Csharp)#

(1)NuGet 引入 SimpleBase 包

(2)简单实现

using System;
using System.Security.Cryptography;
using SimpleBase;
public class SimpleTotp
{
public static string Generate(string base32Secret)
{
// 1. 解码 Base32 密钥
byte[] secret = Base32.Rfc4648.Decode(base32Secret);
// 2. 计算时间计数器 (30秒一个窗口)
long counter = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / 30;
byte[] counterBytes = BitConverter.GetBytes(counter);
if (BitConverter.IsLittleEndian) Array.Reverse(counterBytes);
// 3. HMAC-SHA1
byte[] hash;
using (var hmac = new HMACSHA1(secret))
{
hash = hmac.ComputeHash(counterBytes);
}
// 4. 动态截取
int offset = hash[^1] & 0x0F;
int code = ((hash[offset] & 0x7F) << 24) |
((hash[offset + 1] & 0xFF) << 16) |
((hash[offset + 2] & 0xFF) << 8) |
(hash[offset + 3] & 0xFF);
code %= 1000000;
return code.ToString("D6");
}
}

参考#

  1. 双因素认证(2FA)教程

(完)


支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
了解2FA(双因素认证)
https://mgrowup.com/posts/computer/2fa/
作者
Donghai
发布于
2026-04-28
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Donghai
Hello, I'm Donghai.
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
最新动态
站点统计
文章
62
分类
9
标签
37
总字数
76,949
运行时长
0
最后活动
0 天前
站点信息
构建平台
Vercel
博客版本
Firefly v6.16.5
文章许可
CC BY-NC-SA 4.0