双因素认证(2FA)教程
所谓认证(authentication)就是确认用户的身份,是网站登录必不可少的步骤。
密码是最常见的认证方法,但是不安全,容易泄露和冒充。

越来越多的地方,要求启用 双因素认证(Two-factor authentication,简称 2FA)。本文介绍它的概念和实现方法。

一、双因素认证的概念
一般来说,三种不同类型的证据,可以证明一个人的身份。
- 秘密信息:只有该用户知道、其他人不知道的某种信息,比如密码。
- 个人物品:该用户的私人物品,比如身份证、钥匙。
- 生理特征:该用户的遗传特征,比如指纹、相貌、虹膜等等。
这些证据就称为三种"因素"(factor)。因素越多,证明力就越强,身份就越可靠。
双因素认证就是指,通过认证同时需要两个因素的证据。
银行卡就是最常见的双因素认证。用户必须同时提供银行卡和密码,才能取到现金。
二、双因素认证方案
常用的双因素组合是密码 + 某种个人物品,比如网上银行的 U 盾。用户插上 U 盾,再输入密码,才能登录网上银行。

但是,用户不可能随时携带 U 盾,手机才是最好的替代品。密码 + 手机就成了最佳的双因素认证方案。

国内的很多网站要求,用户输入密码时,还要提供短消息发送的验证码,以证明用户确实拥有该手机。

但是,短消息是不安全的,容易被拦截和伪造,SIM 卡也可以克隆。已经有案例,先伪造身份证,再申请一模一样的手机号码,把钱转走。
因此,安全的双因素认证不是密码 + 短消息,而是下面要介绍的 TOTP。
三、TOTP 的概念
TOTP 的全称是"基于时间的一次性密码"(Time-based One-time Password)。它是公认的可靠解决方案,已经写入国际标准 RFC6238。

它的步骤如下。
第一步,用户开启双因素认证后,服务器生成一个密钥。
第二步:服务器提示用户扫描二维码(或者使用其他方式),把密钥保存到用户的手机。也就是说,服务器和用户的手机,现在都有了同一把密钥。

注意,密钥必须跟手机绑定。一旦用户更换手机,就必须生成全新的密钥。
第三步,用户登录时,手机客户端使用这个密钥和当前时间戳,生成一个哈希,有效期默认为30秒。用户在有效期内,把这个哈希提交给服务器。

第四步,服务器也使用密钥和当前时间戳,生成一个哈希,跟用户提交的哈希比对。只要两者不一致,就拒绝登录。
四、TOTP 的算法
仔细看上面的步骤,你可能会有一个问题:手机客户端和服务器,如何保证30秒期间都得到同一个哈希呢?
答案就是下面的公式。
TC = floor((unixtime(now) − unixtime(T0)) / TS)
上面的公式中,TC 表示一个时间计数器,unixtime(now)是当前 Unix 时间戳,unixtime(T0)是约定的起始时间点的时间戳,默认是0,也就是1970年1月1日。TS 则是哈希有效期的时间长度,默认是30秒。因此,上面的公式就变成下面的形式。
TC = floor(unixtime(now) / 30)
所以,只要在 30 秒以内,TC 的值都是一样的。前提是服务器和手机的时间必须同步。
接下来,就可以算出哈希了。
TOTP = HASH(SecretKey, TC)
上面代码中,HASH就是约定的哈希函数,默认是 SHA-1。
TOTP 有硬件生成器和软件生成器之分,都是采用上面的算法。

(说明:TOTP 硬件生成器)

(说明:Google Authenticator 是一个生成 TOTP 的手机 App)
五、TOTP 的实现
TOTP 很容易写,各个语言都有实现。下面我用 JavaScript 实现2fa来演示一下真实代码。
首先,安装这个模块。
$ npm install --save 2fa
然后,生成一个32位字符的密钥。
var tfa = require('2fa'); tfa.generateKey(32, function(err, key) { console.log(key); }); // b5jjo0cz87d66mhwa9azplhxiao18zlx
现在就可以生成哈希了。
var tc = Math.floor(Date.now() / 1000 / 30); var totp = tfa.generateCode(key, tc); console.log(totp); // 683464
六、总结
双因素认证的优点在于,比单纯的密码登录安全得多。就算密码泄露,只要手机还在,账户就是安全的。各种密码破解方法,都对双因素认证无效。
缺点在于,登录多了一步,费时且麻烦,用户会感到不耐烦。而且,它也不意味着账户的绝对安全,入侵者依然可以通过盗取 cookie 或 token,劫持整个对话(session)。
双因素认证还有一个最大的问题,那就是帐户的恢复。

一旦忘记密码或者遗失手机,想要恢复登录,势必就要绕过双因素认证,这就形成了一个安全漏洞。除非准备两套双因素认证,一套用来登录,另一套用来恢复账户。
七、参考链接
- Multi-factor authentication, by Wikipedia
- Time-based One-time Password Algorithm, by Wikipedia
- Enabling Two-Factor Authentication For Your Web Application, by Bozhidar Bozhanov
- simontabor/2fa, by Simon Tabor
作者: 阮一峰 日期: 2017年11月 2日 感谢阮大神的好帖~~~
双因素认证(2FA)教程的更多相关文章
- 业余草双因素认证(2FA)教程
所谓认证(authentication)就是确认用户的身份,是网站登录必不可少的步骤.密码是最常见的认证方法,但是不安全,容易泄露和冒充.越来越多的地方,要求启用双因素认证(Two-factor au ...
- ASP.NET Core & 双因素验证2FA 实战经验分享
必读 本文源码核心逻辑使用AspNetCore.Totp,为什么不使用AspNetCore.Totp而是使用源码封装后面将会说明. 为了防止不提供原网址的转载,特在这里加上原文链接: https:// ...
- Linux 利用Google Authenticator实现ssh登录双因素认证
1.介绍 双因素认证:双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产生的一 ...
- Linux 之 利用Google Authenticator实现用户双因素认证
一.介绍:什么是双因素认证 双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产 ...
- 轻松搭建CAS 5.x系列(8)-在CAS Server增加双因素认证(DUO版)
概述说明 为了让系统更加安全,很多登录会加入双因素认证.何为双因素,如果把登陆作为开一扇门的话,那就是在原来的锁上再加一把锁,第二锁用新的钥匙,这样安全系数就更加高了. CAS是通过账号名和密码来认证 ...
- java 双因素认证(2FA)TOTP demo
TOTP 的全称是"基于时间的一次性密码"(Time-based One-time Password).它是公认的可靠解决方案,已经写入国际标准 RFC6238. 很早就知道有这个 ...
- 【Linux】使用Google Authenticator 实现ssh登录双因素认证
一般来说,使用ssh远程登录服务器,只需要输入账号和密码,显然这种方式不是很安全.为了安全着想,可以使用GoogleAuthenticator(谷歌身份验证器),以便在账号和密码之间再增加一个验证码, ...
- 操作系统(AIX)双因素身份认证解决方案-中科恒伦CKEY DAS
一.场景分析 操作系统是管理计算机硬件与软件资源的计算机程序,用于工作中的进程管理.存储管理.设备管理.文件管理.作业管理等,十分重要,安全等级极高! 二.问题分析 1.密码设置简单,非常容易被撞 ...
- PyPI提供双因素身份验证(2FA),已提高下载安全性
前天,Python的核心开发团队宣布PyPI现在提供双因素身份验证(2FA),以提高Python包下载的安全性,从而降低未经授权的帐户访问的风险.该团队宣布将在Python Package Index ...
随机推荐
- shell 中各种括号的作用()、(())、[]、[[]]、{}
一.小括号,圆括号 () 1.单小括号 () 命令组.括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用.括号中多个命令之间用分号隔开,最后一个命令可以没有分号, ...
- Windows上使用Git托管代码到Coding
作者:荒原之梦 Git简介: Git是一款分布式版本控制系统,可用于项目的版本管理.Git可以管理本地代码仓库与远程代码仓库间的连接以及进行版本控制,使得我们可以在本地离线进行修改等操作,之后再将代码 ...
- CentOS下使用命令行Web浏览器Links
前言: Links是一个运行在命令行模式下的Web浏览器,只能查看字符.Links的官网是Click here. 安装Links yum install links 使用Links links URL ...
- jQuery学习之旅 Item9 动画效果
1.元素的显示和隐藏 display:none; 隐藏 display:block; 显示 简单显示和隐藏方法 a) show() 显示 b) hide() 隐藏 c) toggle() 开关,显示则 ...
- 『网络の转载』px与em的区别
这里引用的是Jorux的“95%的中国网站需要重写CSS”的文章,题目有点吓人,但是确实是现在国内网页制作方面的一些缺陷.我一直也搞不清楚px与em之间的关系和特点,看过以后确实收获很大.平时都是用p ...
- [SQL Server]用 C# 在 LinqPad 建立 Linked Server 跨服务器数据库操作
在涉及老项目数据迁移的时候,数据库结构已经完全发生变化,而且需要对老数据进行特殊字段的处理,而且数据量较大,使用Navicat导出单表之后,一个表数据大概在100多万的样子,直接导出SQL执行根本行不 ...
- 【bzoj 3306】树
Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Input 第一行两个整数 n, Q ,分别表示树的大小和操作数. ...
- BZOJ_1026_[SCOI2009]windy数_数位DP
BZOJ_1026_[SCOI2009]windy数_数位DP 题意:windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之 ...
- html select 标签设置默认选中
方法有两种. 第一种通过<select>的属性来设置选中项,此方法可以在动态语言如php在后台根据需要控制输出结果. 1 2 3 4 5 < select id = " ...
- Spring Framework学习要点摘抄
以下摘自Spring Framework官方文档,版本Spring 4.3. <context:annotation-config/> implicitly registered post ...