还记得 2023 年 GitHub 强制推行多因子认证(MFA)的那一刻吗?从 3 月开始,GitHub 分阶段要求用户启用 MFA,并在年底前全面完成覆盖,这让全球开发者不得不重新审视身份安全的重要性。
现在我们登录 Github ,除了要输入密码,还需要完成一个额外的验证步骤,比如输入手机上的动态验证码,或者通过手机上的身份验证器(Authenticator App)确认登录。这种看似繁琐的体验已经成为各大云厂商产品的标配。不仅是 GitHub,像 AWS、阿里云、腾讯云等云厂商也几乎都要求在敏感操作时使用多因子认证(MFA),以确保账户安全。
这种举措不仅保护了平台上的代码和账户安全,更体现了现代身份管理技术的趋势,今天,我们就从 GitHub 强制 MFA 的案例切入,了解 MFA 及 Google Authenticator 的实现原理。
在探讨 MFA 之前,我们需要理解身份验证的本质。身份验证是确认某人或某物的身份是否属实的过程。无论是通过密码登录 Gmail,还是刷身份证进入火车站,身份验证的核心都是确保「你是你自称的那个人」。
然而,传统的基于密码的身份验证模式存在诸多隐患:
这些问题导致密码的安全性备受质疑,因此需要额外的保护层,MFA 由此应运而生。
MFA,Multi-Factor Authentication,多因子认证,是一种身份验证方法,要求用户提供多个独立的身份验证因素来完成登录或访问。传统的身份认证只依赖单一密码,MFA 则通过引入额外的验证步骤,极大地提升了账户安全性。
在 MFA 中,通常会结合以下三类验证因素:
MFA 的意义在于,即便攻击者获得了你的密码,由于缺少额外的验证因素,他们依然无法轻易访问你的账户。例如,登录 GitHub 时,即使密码被泄露,攻击者若没有你的手机或安全密钥,仍然无法完成登录。
毕竟,密码泄露已经成为网络攻击中最常见的手段,而 MFA 则为用户的账户增加了第二道甚至第三道锁。
2FA 是MFA 的一种特殊形式,它仅使用两种不同的验证因素来完成认证。简单来说,2FA 是 MFA 的一个子集。
例如:
值得注意的是,两种不同的验证因素是类别的不同,像以前有一种策略是需要提供密码和安全问题答案,这是单因素身份验证,因为这两者都与「你知道的东西」这个因素有关。
在大多数应用中,2FA 已经足够满足安全需求,因此它是目前最常见的多因子认证实现方式。
随着技术的进步,密码破解的门槛越来越低。攻击者可以通过以下方式轻松破解密码:
在这种背景下,仅靠密码保护账户变得极为不可靠。MFA 通过引入多层保护,从根本上提升了安全性。
MFA 的最大优势在于,它大幅提高了攻击者的攻击成本。例如,攻击者即便成功窃取了用户密码,也需要物理接触用户的手机或破解生物特征才能完成登录。这种额外的复杂性往往会使攻击者放弃目标。
MFA 可以有效抵御多种网络威胁,包括:
MFA 形式多样,主要有如下的一些形式:
双因素身份验证的核心理念是:即使攻击者获得了用户的密码,他仍然需要通过第二道验证关卡才能访问账户。以下是 2FA 的典型工作流程:
如当你登录阿里云时,输入密码后需要打开阿里云的 APP,输入 MFA 的验证码。
尽管 MFA 极大地提高了账户安全性,但它并非万能。有如下的一些局限性:
用户体验问题:对于技术不熟练的用户来说,设置和使用 MFA 应用程序门槛比较高。此外,每次登录需要额外的验证步骤,也可能降低用户体验。
成本问题:企业需要支付额外的费用来实施 MFA。例如短信验证需要支付短信发送费用,而硬件令牌的采购和分发也需要额外开支。
并非百分百安全:MFA 虽然有效,但并非无懈可击。例如:
在了解了概念后,我们看一下我们常用的一个 MFA 验证应用 Google Authenticator 的实现原理。
在使用 Google Authenticator 进行 2FA 的过程中,验证的过程可以分为以下两个主要阶段:初始化阶段 和验证阶段。
这是用户首次启用双因素身份验证时发生的过程。在此阶段,服务端生成共享密钥(Secret Key)并通过安全的方式分发给用户的 Google Authenticator 应用。
服务端生成共享密钥:
K
(通常是 16~32 个字符的 Base32 编码字符串,例如JBSWY3DPEHPK3PXP
)。生成二维码:
Example
: 服务提供方的名称。username@example.com
: 用户的账户。在 github 的场景中这个字段是没有的。SECRET=JBSWY3DPEHPK3PXP
: 共享密钥。issuer=Example
: 服务提供方名称(用于显示在 Google Authenticator 中)。服务端将共享密钥和其他元信息(如站点名称、用户账户)打包成一个 URL,符合otpauth://
协议格式,例如:
otpauth://totp/Example:username@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
其中:
该 URL 会被编码为一个二维码,供用户扫描。
用户扫描二维码:
K
)以及站点相关信息,并将其安全存储在手机本地。初始化完成:
K
和当前时间生成动态密码。K
绑定到用户账户,并妥善保存以便后续验证使用。这是用户登录时的验证过程。在此阶段,客户端和服务端基于相同的共享密钥K
和时间步长计算动态密码,并进行验证。
获取当前时间:
将时间戳转换为时间步长:
T = floor(currentUnixTime / timeStep)
例如,当前时间是1697031000
秒,时间步长为 30 秒,则:
T = floor(1697031000 / 30) = 56567700
计算 HMAC-SHA-1 哈希值:
T
转换为 8 字节的 Big-endian 格式(例如0x00000000056567700
)。K
和时间步长T
作为输入,计算 HMAC-SHA-1 哈希值:
HMAC = HMAC-SHA-1(K, T)
结果是一个 20 字节(160 位)的哈希值。
截断哈希值:
offset
。取模生成动态密码:
10^6
,生成 6 位数字密码:
OTP = DBC % 10^6
例如,计算结果为123456
。
显示动态密码:
服务端获取当前时间:
T
。计算候选动态密码:
K
和当前时间步长T
,通过与客户端相同的 TOTP 算法计算动态密码。T
以及前后几个时间步长(例如T-1
和T+1
)的动态密码,形成候选密码列表。验证动态密码:
在整个验证过程中,关键数据的传递和使用如下:
客户端:
K
和当前时间计算动态密码。客户端 → 服务端:
服务端:
K
和时间步长计算候选动态密码。整个过程有如下的一些关键点:
共享密钥的安全性:
K
是整个验证过程的核心,必须在初始化阶段通过安全的方式传递,并在客户端和服务端妥善保存。时间同步:
T
会不一致,导致动态密码验证失败。动态密码的短生命周期:
离线生成:
通过 GitHub 强制推行 MFA 的案例,我们可以清晰地看到,MFA 已经成为现代身份管理的重要基石。密码本身的弱点让账户安全长期处于威胁之下,而 MFA 的引入不仅为用户增加了一层甚至多层防护,更在技术上为身份验证树立了一个全新的标准。
尽管 MFA 并非完美,还存在用户体验、实施成本和一定的攻击风险,但它在密码安全性危机中提供了一种强有力的解决方案。无论是个人用户还是企业,采用 MFA 已经成为抵御网络威胁的必要手段。
未来,随着技术的进一步发展,多因子认证可能会越来越多地融合生物特征、行为分析和人工智能技术,为用户提供更安全且更便捷的身份验证体验。而对于每一位开发者和用户来说,理解和使用这些技术,不仅是保护自身数字资产的关键,更是应对日益复杂的网络安全形势的必修课。
以上。