大家好,我是vzn呀,又见面了。

随着互联网在生活方方面面的应用,日常少不了要登录各个网站或者应用、或者是银行转账等需要验证自己身份的场景。从早期的输入账号密码来登录,到后来普遍开始通过手机验证码进行登录、或者APP扫码进行登录,身份校验的操作方式经历了一轮又一轮的迭代演进。

近年来,有越来越多的网站开始推广并引导用户启用所谓的2FA双重登录验证,比如Github就早在2022年的时候就开始引导用户启用2FA,近期还发出警告若用户在2024年10月22日前未启用2FA将被限制部分功能。而科技巨头Apple在最近发布的IOS18中,也亮相了全新的密码APP并提供对于2FA场景的临时鉴权码(IOS中称为验证码)生成的能力支持。

这个2FA究竟是何方神圣?为什么越发得到各大公司的青睐、甚至是Apple也要亲自入局?本篇文章我们就来一探究竟。

初识2FA

所谓2FA,也即双因素认证(Two-Factor Authentication,简称2FA),是一种身份校验的策略。顾名思义,所谓双因素认证,就是你需要同时提供2方面的证据、来证明你就是你。

想要验证一个人是否为本人,用户提供的证据(认证因素)大体可分为3类:

分类 说明 举例
私有秘密 一个私密的信息,仅本人可知晓的内容,知晓此内容即认为是合法的目标身份 最为常见,比如密码、密钥等
生理特征 基于人的各种独一无二的生理特征,来判断并确定是否为本人 比如人脸、指纹、声纹、虹膜等
专有物件 一个私人专属的物理设备或物件,持有此物件的人就是本人 身份证、手机、U盾等

任一认证因素都可以作为个人身份的认证,但又都有各自的缺点,无法做到100%可靠精准。

  1. 使用账号密码登录: 存在密码泄露的风险。尤其是很多人喜欢所有账号都同一个密码,一旦泄露,后果不堪设想。
  2. 使用人脸识别: 应用门槛高,需要硬件层面支持,web类应用难以应用。此外,生物特征属于不可变更类型,如果生物特征泄露将无法变更,后果比密码泄露更严重。
  3. 使用U盾等专有物件:成本高、便捷度差,不仅要携带设备,一旦丢失还很麻烦。

所以,为了尽可能的提升认证结果的可信度,弥补单一认证因素存在的弊端,2FA认证方案应用而生。通过同时使用2种认证因素进行综合识别,来提升识别结果的可信度,保障身份认证的安全性。

话说到这里,既然单一认证有风险,2FA可以将风险降低,那为啥不直接搞个3FA呢?岂不是更加安全吗?这其实是软件实现中常见的一种取舍,毕竟软件最终是要服务于用户使用的,还是需要关注下用户使用的便捷度与使用体验,所以2FA相对而言,就是在安全和便捷之间取了个折中。

2FA的形态演进

2FA并非是一个新鲜玩意,它很早就已经开始广泛应用在各种场景中了。随着时间的推移,其呈现形式也经历了数次的演进,服务接入门槛降低、用户使用的繁琐度也大幅下降。

下面举几个2FA的实际应用,感受下这些年2FA技术的变革。

  • 早期网上银行的U盾

早些年的时候,开通网上银行的时候,银行会提供一个类似U盘形状的U盾,或者是一个密码生成器(估计很多年轻小朋友都没见过,也算是时代的眼泪吧~)。在需要转账的时候,除了要输入自己的银行卡号和取款密码,还需要将U盾插入到电脑上,或者用密码生成器生成一串数字,并将数字填入到网页中进行双重校验之后,才会允许转账操作。

这种2FA的应用场景中,分别使用了密码和独立物理设备进行综合认证。有效的规避了密码泄露或者U盾丢失带来的风险(当然,U盾和密码同时被另一个人拿到的话,就回天乏术了),保障个人资金的安全。

这种方式,虽然达到了账号安全性的要求,但是弊端也很明显:

  1. 实施门槛高,需要生产配套物理设备,所以仅在银行这种财大气粗的行业领域中使用,很难在各行业中普遍推广。
  2. 用户使用繁琐,如果设备不在身边或者丢失,则无法使用。而且,不同银行之间、甚至同一个银行的不同银行卡之间都有配套独立的设备,保存并区分也是一件很头疼的事情。

也是由于上述的原因,现在几乎已经看不到U盾的身影了。

  • 网站登录采用账密+手机验证码方式

这个是目前比较常见的一种2FA的应用形态。比如某度网盘,输入账号和密码验证通过后,还会要求向手机发送验证码,基于验证码进行二次身份认证通过之后,方可正常登录到系统中。

这种形态,其实算是早期的密码+U盾设备的一种升级方案。前面也说过了基于U盾等物理设备进行认证的成本与使用繁琐问题,而当前手机已经成为用户必备且几乎形影不离的物件,它便是U盾等设备的最佳替代品。

基于密码+手机验证码的方式,在提升认证安全性的同时,打破了对特定配套物理设备的依赖,降低了2FA方案的落地成本与用户使用体验,被广泛的应用到了各种在线身份认证的场景中,成为了当前最为主流的一种2FA认证方式。

但是利用手机验证码进行验证,依旧会存在一个成本问题,毕竟发送短信也是要钱的,尤其是对于一些几亿用户体量的系统而言,即使每个用户1个月只发送一条短信,算下来也是一笔不菲的费用啊。

  • iCloud网页版登录

apple用户如果登录过网页版iCloud,应该都有见过iCloud的2FA实现思路,它在验证完用户的账号和密码之后,并非是发送短信验证码,而是向登录了此账号的iphone设备推送了一条弹窗通知,里面显示了一串随机码,用户输入iPhone接收到的随机码,完成身份验证并进入到系统重。

苹果的这种实现,借助自身iPhone设备的广泛应用,构建了服务端与iPhone设备之间的专有推送通道,完美的省掉了短信验证码发送的费用。但,这种方案,就像网上很多人调侃苹果的那句Only Apple Can Do一样,还真的只有Apple等手机设备厂商可以实现。对于普通的系统服务提供者,想要通过非短信途径推送验证码给用户,也至少得要用户在手机中安装个自己产品的APP应用,才有可能实现利用自己的通道进行点对点消息推送,但这一条件显然限制了该方案的推行。

总体而言,iCloud的这种做法,是一种更加经济的2FA方案,但是技术门槛与推广门槛极高,不具备普遍性。

  • GitHub网站登录

并不是所有公司都是手机厂商。所以是否有一种通用的、成本更低廉的2FA实现方案呢?在这个背景下,一种基于TOTP协议的2FA方案进入大众视野中。当前很多启用2FA的网站,使用的都是这一方案。

看下GitHub的2FA登录实现。在开启2FA功能的时候,需要在提前在手机上安装一个APP并绑定到GitHub账号上。这样后续在输入账号密码之后,还需要打开APP并将APP中生成的鉴权码填入到界面上进行二次验证,验证通过之后方可进入系统。

这里的手机上安装的APP,也是基于TOTP协议进行开发的密钥生成器。这一方案接入成本相对较低、更容易推广,目前正在逐步被各类系统所支持。值得一提的是,正如本文开头提及的消息,在9月中旬刚刚发布的IOS18系统中自带了一款名为密码的APP,其中提供了一个验证码功能,也正是基于TOTP协议的鉴权码生成器,使用它生成的验证码也可以正常完成2FA认证。

基于TOTP的2FA

在上面介绍GitHub的2FA方案的时候,有提过其采用的是基于TOTP算法的2FA方案。所谓TOTP,即基于时间的一次性密码(Time-based One-Time Password,简称TOTP),它是一种国际标准协议(RFC6238)。其本质上就是取当前时间戳以及当前账号的一个唯一标识(类似密钥,服务端颁发、并提供给客户端保存使用),通过固定算法加工生成一个6位数的鉴权码,一定时间范围内生成的鉴权码是固定的(所以这个验证码会有个有效期的概念,一般是30s)。这样只要服务端和APP端各自计算出一个验证码,然后比对下两个验证码是否一致,即可完成校验。


def generate_totp(secret, interval=30, digits=6, timestamp=None):
"""
生成基于时间的一次性密码(TOTP)。 :param secret: 密钥(base32 编码的字符串)
:param interval: 时间间隔(秒)
:param digits: 生成的 OTP 的位数
:param timestamp: 当前时间戳(秒),默认为当前时间
:return: 生成的 OTP 字符串
"""
if timestamp is None:
timestamp = int(time.time()) # 计算时间步长(时间戳除以时间间隔并取整)
counter = timestamp // interval # 将时间步长转换为字节序列
counter_bytes = struct.pack('>Q', counter) # 使用 HMAC-SHA1 生成哈希值
hmac_result = hmac.new(base64.b32decode(secret), counter_bytes, hashlib.sha1).digest() # 动态截断以生成 OTP
offset = hmac_result[-1] & 0xf
binary_otp = hmac_result[offset:offset + 4]
binary_otp = struct.unpack('>I', b'\x00' + binary_otp[1:3] + b'\x00')[0] # 将 OTP 格式化为指定位数的字符串
otp = str(binary_otp % 10**digits).zfill(digits) return otp def main():
# 示例密钥(base32 编码)
secret = 'JBSWY3DPEHPK3PXP' # 生成当前时间的 TOTP
otp = generate_totp(secret)
print(f"Generated TOTP: {otp}") # 验证生成的 OTP(假设客户端和服务器的时间同步)
verified_otp = input("Enter the OTP you received: ")
if otp == verified_otp:
print("Verification successful!")
else:
print("Verification failed!") if __name__ == "__main__":
main()

基于上面介绍,可以看出,基于TOTP算法生成验证码有两个输入因子:时间和用户密钥。服务端和客户端除了需使用相同的加密算法,还需要保证传入相同的时间戳和用户密钥,才能保证生成的校验码相同。如何保证服务端和客户端设备,可以获取到相同的参数值呢?下面简单介绍下。

  • 时间因子

服务端和客户端在计算生成验证码的时候,各自取自身设备本地当前时间作为时间参数。因为如今的智能手机和服务器都支持基于网络的时钟校准能力,所以可以很轻松的保证手机终端与应用服务端本地时间的基本一致。

  • 用户密钥因子

用户密钥因子是服务端为用户生成的授权密钥,计算生成验证码的时候,服务端和客户端都要使用同一个密钥进行计算,所以服务端为用户生成密钥后,除了服务端要保存该密钥与用户的绑定关系,还需要将此密钥提供给用户、由用户将其绑定到手机上的TOTP软件中(所谓绑定,本质上就是将服务端生成的密钥存储到手机的TOTP软件中)。绑定完成后,服务端和客户端就都拥有相同的用户密钥信息了。

至此,TOTP算法所需的2个关键参数都已具备,就可以使用TOTP应用生成的验证码进行身份二次认证咯。

讲到这里,小伙伴们可能会有个疑惑,假如用户更换了新手机,新手机上安装的TOTP软件并没有绑定对应的用户密钥信息,那不就没法登录了吗?

这就要再回到开启2FA认证的时候,服务端除了会生成一个密钥(类似公钥)提供给客户端进行绑定,还会同时提供一份Recovery Code,会提示用户将其可靠保存起来。

目前市面上主流的基于TOTP的客户端软件,主要有2个:

  • Google Authenticator
  • MicroSoft Authenticator

当然,现在又多了个Apple Password,以后可能会形成三足鼎立的局面。

服务中集成2FA能力

如果需要在服务端开启2FA能力,需要集成实现对应的TOTP密钥算法即可。以JAVA为例,可以通过集成现有的第三方库来快捷实现,常用的有com.warrenstrange.googleauth库:

<dependency>
<groupId>com.warrenstrange</groupId>
<artifactId>googleauth</artifactId>
<version>{version}</version>
</dependency>

代码中直接使用其提供的api接口即可,下面代码演示下api接口的使用方式:

import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.IKey;
import com.warrenstrange.googleauth.KeyGenerator; import java.time.Instant; public class TOTPExample {
public static void main(String[] args) {
// 生成一个密钥、可以指定密钥长度,例如20字节
IKey key = KeyGenerator.getKey(20);
String secretKey = key.getKey();
// 计算当前时间的时间窗口
long currentTime = Instant.now().getEpochSecond();
int timeStep = 30;
long timeWindow = currentTime / timeStep;
// 生成TOTP
GoogleAuthenticator ga = new GoogleAuthenticator();
String totp = ga.getTotpPassword(secretKey, timeWindow);
System.out.println("Generated TOTP: " + totp); // 校验验证码是否符合预期
boolean isValid = ga.authorize(totp, secretKey, timeWindow);
System.out.println("TOTP Validation: " + (isValid ? "Success!" : "Failed!")); // 考虑到网络延迟等因素,可以允许一定的时间误差。例如,验证时允许前后一个时间窗口的误差
boolean isValidWithTolerance = false;
for (int i = -1; i <= 1; i++) {
long toleranceWindow = timeWindow + i;
if (ga.authorize(totp, secretKey, toleranceWindow)) {
isValidWithTolerance = true;
break;
}
}
System.out.println("TOTP Validation with Tolerance: " + (isValidWithTolerance ? "Success!" : "Failed!"));
}
}

总结

好咯,关于双因素认证的内容,就聊到这里,相信小伙伴们对2FA已经有所了解了吧。随着互联网时代对个人信息与隐私的日益重视、以及现今网络安全形势的日益严峻,用户身份认证的技术方案与实现形态也在不断地发展与优化,相信2FA在后续也会得到更大的普及。关于2FA或者用户身份验证的方案,小伙伴们是否有自己的见解呢,欢迎留言交流。

我是vzn呀,聊技术、又不仅仅聊技术~

如果觉得有用,请点个关注,也可以关注下我的公众号【是vzn呀】,获取更及时的更新。

期待与你一起探讨,一起成长为更好的自己。

使用越来越广泛的2FA双因素认证,缘何越发受到推崇?的更多相关文章

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

    所谓认证(authentication)就是确认用户的身份,是网站登录必不可少的步骤.密码是最常见的认证方法,但是不安全,容易泄露和冒充.越来越多的地方,要求启用双因素认证(Two-factor au ...

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

    所谓认证(authentication)就是确认用户的身份,是网站登录必不可少的步骤. 密码是最常见的认证方法,但是不安全,容易泄露和冒充. 越来越多的地方,要求启用 双因素认证(Two-factor ...

  3. 用Abp实现双因素认证(Two-Factor Authentication, 2FA)登录(一):认证模块

    @ 目录 原理 用户验证码校验模块 双因素认证模块 改写登录 在之前的博文 用Abp实现短信验证码免密登录(一):短信校验模块 一文中,我们实现了用户验证码校验模块,今天来拓展这个模块,使Abp用户系 ...

  4. Linux 利用Google Authenticator实现ssh登录双因素认证

    1.介绍 双因素认证:双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产生的一 ...

  5. Linux 之 利用Google Authenticator实现用户双因素认证

    一.介绍:什么是双因素认证 双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产 ...

  6. 轻松搭建CAS 5.x系列(8)-在CAS Server增加双因素认证(DUO版)

    概述说明 为了让系统更加安全,很多登录会加入双因素认证.何为双因素,如果把登陆作为开一扇门的话,那就是在原来的锁上再加一把锁,第二锁用新的钥匙,这样安全系数就更加高了. CAS是通过账号名和密码来认证 ...

  7. java 双因素认证(2FA)TOTP demo

    TOTP 的全称是"基于时间的一次性密码"(Time-based One-time Password).它是公认的可靠解决方案,已经写入国际标准 RFC6238. 很早就知道有这个 ...

  8. 【Linux】使用Google Authenticator 实现ssh登录双因素认证

    一般来说,使用ssh远程登录服务器,只需要输入账号和密码,显然这种方式不是很安全.为了安全着想,可以使用GoogleAuthenticator(谷歌身份验证器),以便在账号和密码之间再增加一个验证码, ...

  9. ASP.NET Core & 双因素验证2FA 实战经验分享

    必读 本文源码核心逻辑使用AspNetCore.Totp,为什么不使用AspNetCore.Totp而是使用源码封装后面将会说明. 为了防止不提供原网址的转载,特在这里加上原文链接: https:// ...

  10. 操作系统(AIX)双因素身份认证解决方案-中科恒伦CKEY DAS

      一.场景分析 操作系统是管理计算机硬件与软件资源的计算机程序,用于工作中的进程管理.存储管理.设备管理.文件管理.作业管理等,十分重要,安全等级极高! 二.问题分析 1.密码设置简单,非常容易被撞 ...

随机推荐

  1. LaTeX 魔法注释

    LaTeX magic comments,有点像 shebang,不过与 shebang 有细微区别,不要搞混. % !TeX root = main.tex % !TeX program = xel ...

  2. Ubuntu 设置 SMB 服务

    安装 Samba 包 sudo apt install samba samba-common 创建用于 SMB 共享的文件夹 sudo mkdir /usr/local/volumes # 新建用于共 ...

  3. 一个小小空格问题引起的bug

    程序员会遇到一种情况,一个bug排查到最后是由一个很小的问题导致的.在昨天的日常搬砖中遇到一个问题,耽搁了我大半天的时间,最后查明原因让我很无语. 首先介绍一下背景,我是做算法模型训练,目前手上的工作 ...

  4. elastersearch7.6.1搭建及基本操作详解

    搭建 修改系统参数 vim /etc/security/limits.conf * soft nofile 655350 * hard nofile 655350 * soft nofile 6553 ...

  5. 【Docker学习系列】Docker学习2-docker设置阿里云镜像加速器

    在上一篇中,我们学会了在centos中安装docer.我们知道,镜像都是外网的,镜像一般都是比较大的,因为种种原因,我们知道,从外网下载比较慢的.所以,本文,凯哥就介绍怎么将docker的镜像拉取设置 ...

  6. Scikit-learn从入门到放弃

    目录 Scikit-learn简介 SVM分类 随机森林回归 K-means聚类 前置建议阅读: 1.NumPy从入门到放弃 2.Pandas从入门到放弃 3.SciPy从入门到放弃 Scikit-l ...

  7. sharepoint 打开rdl报表,报表服务器数据库内出错。此错误可能是因连接失败、超时或数据库中磁盘空间不足而导致的

    最近在做reporting services报表的时候,部署到sharepoint后,打开rdl报表,经常遇到一个问题: 报表服务器数据库内出错.此错误可能是因连接失败.超时或数据库中磁盘空间不足而导 ...

  8. CSS & JS Effect – Section Design Waves

    介绍 Section Waves 长这样       左边是没有 waves, 右边是加了 waves. 它的作用就是点缀. 让画面有一点 "Design" 的感觉. 参考 You ...

  9. Trace32 simulator调试以及简单实用命令介绍

    目录 Trace32 Simulator debug Trace32工具配置 Trace32命令简介 memory class 常见命令索引 v.v使用实例 不同CPU运行信息查看 Trace32 S ...

  10. windows下查看用户名

    net user 查看计算机所有用户名 echo %username% 查看当前用户名