Skip to content
Donghai's Blog
Go back

2FA

Updated:

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

Table of contents

Open Table of contents

概念

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

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

2FA 方案

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

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

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

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

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

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

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

TOTP的算法

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

TC = floor((unixtime(now)  unixtime(T0)) / TS)

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

TC = floor(unixtime(now) / 30)

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

TOTP = HASH(SecretKey, TC)

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

另外,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)教程

(完)

如果这篇文章刚好帮到了你,欢迎请我喝杯咖啡


分享这篇文章:

上一篇
2026年跑步日志(5月开始)
下一篇
抖音创作日志(2026年)
BlogsClub Meo Forever Blog