使用两步验证提高账号安全性

标签: 两步验证 安全 | 发表时间:2015-05-31 14:31 | 作者:
出处:https://www.imququ.com

很早之前我的 dnspod 账号被盗过,导致域名被人通过 Api 设置了泛解析,指向了一堆垃圾网站。从那之后我终于痛下决心,把常用的 WEB 服务全部梳理了一遍,使用各不相同的密码(Mac 和 iPhone 上我都买了 1Password,用来生成和管理这些密码)。对于支持两步验证的网站,我一定会启用它。最近,imququ.com 这个我基于 ThinkJS 开发的博客系统,后台登录也启用了两步验证。本文来讨论有关两步验证的话题。

什么是两步验证

两步验证,对应的英文是 Two-factor Authentication(2FA),有些地方也称之为 Two-step Verification,它跟 OAuth 2.0 没有关系,不要搞混了。从名字可以看出,「两步」是 2FA 的重点,广义的 2FA 是指提供多种方案完成用户权限鉴定。例如某些网站,在验证完用户名和密码之后,还需要输入手机收到的校验码才能登录成功;某些安全性要求比较高的场景,比如银行网银或者 VPN,会单独提供一个硬件设备辅助完成用户权限认证。这都是 2FA。

我们知道,登录非 HTTPS 网站时,用户名密码都是明文传输,很容易被人截获。即使采用了 HTTPS,如果电脑被装了键盘记录器,或者浏览器被装了不良扩展,密码还是会被盗。两步验证解决的问题是:即使用户名密码输入正确,还需要输入额外的校验码才能登录;而这个校验码是一次性的,即使在传输过程中被拦截到也不要紧。既然用户电脑环境并不一定安全,网站需要使用其他途径分发校验码,例如通过短信、电话、硬件设备,才能保证最终的安全。

这个网站列出了哪些网站支持 2FA,哪些不支持,以及各自支持生成校验码的方式。从这个列表中可以看到,大部分国外知名 WEB 服务都支持 2FA。这个列表最后一列,是指用软件实现的 2FA。它的工作原理是网站为每个用户生成一个密钥,用户手机需要安装能根据这个密钥算出校验码的软件,用户通过算好的校验码,在网站上完成额外的验证。这种方案成本低廉,使用方便,得到了大部分网站的支持。

HOTP 和 TOTP

前面说过,2FA 中使用的是一次性密码(One Time Password,OTP),也被称作动态密码。一般 OTP 有两种策略:计次使用和计时使用。计次使用的密码使用过一次就失效;计时使用的密码过一段时间就失效。

HOTP 的全称是 HMAC-based One Time Password,它是基于 HMAC 的一次性密码生成算法。HMAC 的全称是 Hash-based Message Authentication Code,是指密钥相关的哈希运算消息认证码。HMAC 利用 MD5、SHA-1 等哈希算法,针对输入的密钥和消息,输出消息摘要。HOTP 算法中,传入密钥 K 和计数器 C,得到数字校验码。

实际使用 HOTP 中,服务端会给用户生成密钥 K,并约定起始计数器 C。客户端根据 K 和 C 生成校验码,并在用户点击刷新按钮后将计数器加 1,同时更新校验码;而服务端会在每次校验成功后将计数器加 1,这就保证了校验码只能使用一次。但客户端刷新并不通知服务端,很可能出现客户端计数器大于服务端的情况。所以一般的实现里,服务端如果用 PASSWORD = HOTP(K, C) 验证失败,还会尝试 C+1、C+2...,如果匹配上了,就更新服务端的计数器,保证跟客户端步调一致。出于安全考虑,服务端会设置一个最大值,并不会无限制地尝试下去。

HOTP 的优点是可以事先算好一批校验码,用户可以把他们打印出来随身携带逐个使用,用一个划掉一个,达到客户端计数器累加的效果,这样可以完全不依赖于电子设备。HOTP 的缺点是计数器很容易不一致,服务端经常需要通过不断尝试来同步计数器,从而降低了安全性。

TOTP 的全称是 Time-based One-time Password,它是基于时间的一次性密码生成算法。TOTP 算法需要约定一个起始时间戳 T0,以及间隔时间 TS。把当前时间戳 now 减去 T0,用得到的时间差除以 TS 并取整,可以得到整数 TC。根据 PASSWORD = HOTP(K, TC) 就可以得到数字校验码。

TOTP 实际上只是把 HOTP 的递增计数器换成了与当前时间有关的 TS,从而在服务端 / 客户端时间一致的前提下,解决了 HOTP 需要同步计数器的问题。同时,TOTP 算法需要用到当前时间,需要现场计算,无法提前算好打印出来。默认情况下,TOTP 在间隔时间 TS 内都能通过校验,并不是一次有效。这个问题可以通过在服务端记录最后一次 TC 来解决,由于 TS 一般很短,通常也可以忽略。

在 Node 中使用

有一个名为 speakeasy 的 Node 包,可以用来生成 HOTP 或 TOTP,直接通过 npm install speakeasy 就能安装。Google 出品了一个名为 Authenticator 的客户端,支持 HOTP 和 TOTP,适用于各大移动平台。这里就以 speakeasyGoogle Authenticator 为例说明如何在 Node 中使用 2FA。

生成密钥

首先,通过以下代码可以生成密钥 K:

  var speakeasy = require('speakeasy');
var key = speakeasy.generate_key({});
console.log(key);

{ 
  ascii: '@H?e#/)iOxS65k09h8g2DJ?/EavR7CCs',
  hex: '40483f65232f29694f785336356b303968386732444a3f2f4561765237434373',
  base32: 'IBED6ZJDF4UWST3YKM3DK2ZQHFUDQZZSIRFD6L2FMF3FEN2DINZQ'
}

speakeasy 默认会生成三种格式的密钥,其中 Google Authenticator 需要用到 base32。服务端需要为每个用户生成并存储密钥。

生成二维码

上面一步生成的密钥,用户可以在 Google Authenticator 里手动录入,更方便的做法是把密钥转成二维码。Google Authenticator 支持的二维码格式是:

  otpauth://TYPE/LABEL?PARAMETERS

TYPE 支持 hotp 或 totp; LABEL 用来指定用户身份,例如用户名、邮箱或者手机号,前面还可以加上服务提供者,需要做 URI 编码。它是给人看的,不影响最终校验码的生成。

PARAMETERS 用来指定参数,它的格式与 URL 的 Query 部分一样,也是由多对 key 和 value 组成,也需要做 URL 编码。可指定的参数有这些:

  • secret:必须,密钥 K,需要编码为 base32 格式;
  • algorithm:可选,HMAC 的哈希算法,默认 SHA1。Google Authenticator 不支持这个参数;
  • digits:可选,校验码长度,6 位或 8 位,默认 6 位。Google Authenticator 不支持这个参数;
  • counter:可选,指定 HOTP 算法中,计数器 C 的默认值,默认 0;
  • period:可选,指定 TOTP 算法中的间隔时间 TS,默认 30 秒。Google Authenticator 不支持这个参数;
  • issuer:可选(强烈推荐),指定服务提供者。这个字段会在 Google Authenticator 客户端中单独显示,在添加了多个服务者提供的 2FA 后特别有用;

另外,Google Authenticator 也不支持指定 TOTP 算法中起始时间戳 T0。下面是两个完整的例子,将他们生成二维码,通过 Google Authenticator 扫描就可以添加进去了:

  otpauth://hotp/TEST:[email protected]?secret=IBED6ZJDF4UWST3YKM3DK2ZQHFUDQZZSIRFD6L2FMF3FEN2DINZQ&issuer=ququblog&counter=0
otpauth://totp/TEST:[email protected]?secret=IBED6ZJDF4UWST3YKM3DK2ZQHFUDQZZSIRFD6L2FMF3FEN2DINZQ&issuer=ququblog

有关 Google Authenticator 二维码格式的更多说明,可以参考 官方 wiki

服务端验证

以下代码分别可以生成 HOTP 和 TOTP,用于服务端验证用户提交的校验码是否正确。需要注意的是,代码中的 key 参数默认是 ascii 格式,传其他格式需要指定 encoding 参数。

  speakeasy.hotp({ key : key.ascii, counter : counter};

speakeasy.totp({ key : key.ascii});

服务端根据用户信息读出密钥(针对 HOTP 还需要读出最新的计数器),算出服务端校验码,跟用户提交的校验码比较,如果一致就验证通过。针对 HOTP,验证失败需要尝试同步计数器;验证通过需要更新服务端计数器。

安全风险讨论

最后我打算聊一聊我能想到的关于 OTP 的安全风险点:

首先,无论是 HOTP 和 TOTP,在服务端验证时需要用到密钥,这就需要在服务端存储密钥,如果服务端代码或者数据库发生泄露,密钥可能会被人拿到。其次,生成二维码这一步也需要用到密钥,如果用户电脑存在恶意软件,也存在密钥泄露的风险。另外,手机 2FA 客户端也需要存储密钥,如果安全防护没做好,也有密钥被其他 APP 盗取的风险(所以从正规途径下载知名公司开发的 2FA 客户端,并且手机不要越狱或 ROOT 很重要)。后两个问题,使用独立的 OTP 硬件设备应该能解决。

但是,无论是何种 OTP,一定会存在需要禁用 OTP,或者更换密钥的场景(例如 HOTP 中计数器达到最大值,手机丢失或 OTP 硬件设备丢失),如果这里考虑不周,一样会影响账户安全。所以,WEB 安全也是一个系统工程,各方面都需要考虑周全。

本文链接: https://www.imququ.com/post/about-two-factor-authentication.html参与讨论

推荐: 领略前端技术 阅读奇舞周刊

相关 [两步验证 安全] 推荐:

使用两步验证提高账号安全性

- - JerryQu 的小站
很早之前我的 dnspod 账号被盗过,导致域名被人通过 Api 设置了泛解析,指向了一堆垃圾网站. 从那之后我终于痛下决心,把常用的 WEB 服务全部梳理了一遍,使用各不相同的密码(Mac 和 iPhone 上我都买了 1Password,用来生成和管理这些密码). 对于支持两步验证的网站,我一定会启用它.

谷奥: Google 向所有用户开放两步验证功能

- Dolphin - 谷奥聚合——谷奥主站+谷安 aggregator
Google 在去年9月份向 Google Apps 付费用户开放的两步验证登录机制终于面向所有 Google 用户开放了. 进入账户管理页面,你应该可以看到一个全新的 Using 2-step verification 链接,点击即可对此功能进行设置. 两步验证机制对于某些对账户安全性要求较高的用户是非常有必要的,并且 Android / iPhone / Blackberry 都可以使用专用 App 生成验证码而绕过短信验证方式,关于更多的两步验证机制的介绍请参考谷奥之前的报道.

Google 的两步验证机制已向全球开放

- Yousri - 谷奥——探寻谷歌的奥秘
在今年2月在美国开始提供两步验证登录之后,今天Google将其扩展到全球,开始支持150个国家和40种语言. 不过如果你不是什么敏感词人士的话,没必要用这个两步验证,因为它确实很麻烦. 一旦你打开了两步验证机制,你在登录Google服务的时候除了需要输入以前的密码以外,还要输入一个临时通过手机应用或短信或语音电话告知的临时登录码(众所周知景德镇人士不要用短信或语音来获得这个登陆码,通过手机应用获得是最好的,因为信息的传输是加密的,支持iPhone、Android和黑莓).

Google账户两步验证的工作原理【转】

- - 行业应用 - ITeye博客
      最近在考虑一些用户登录验证的问题,现阶段在涉及到一些交易时,基本上都使用的是短信验证码验证,但有朋友说,有些时候短信验证码会出现延时,不及时. 于是就看了一下Google Authenticator(coogle账户两步验证)技术. 如下是从一位网友那里转来的该技术的原理描述,做个标记,方便查找.

谁更安全?

- iceman.yu - 比特客栈的文艺复兴
原文:The triumph of coal marketing – Seth Godin. 翻译+整理:David Frank. 你对核能发电是不是也有一些看法. 相比其他的发电方式,它们谁更安全. 数据来自这里,图片来自这里,上图是一幅毫不夸张的数据简化图. 同样的发电量,每当核能发电误杀一个人,煤炭发电会导致4,000人的死亡.

网络安全

- - CSDN博客系统运维推荐文章
1、防止入侵者对主机进行ping探测,可以禁止Linux主机对ICMP包的回应.  iptables 防火墙上禁止ICMP应答.  关闭不必要的端口,时常检查网络端口情况.  nmap  可以扫描端口.  关闭不必要的服务和端口.  为网络服务指定非标准的端口.  开启防火墙,只允许授权用户访问相应的服务端口.

安全机制

- - 开源软件 - ITeye博客
ActiveMQ中所有安全相关的概念都是通过插件的形式实现的.这样可以通过ActiveMQ的XML. 配置文件的元素来简化配置和自定义安全认证机制.ActiveMQ提供两种认证方式:.     简单认证插件 -- 直接通过XML配置文件或者属性文件处理认证.     JAAS认证插件 -- 实现了JAAS API,提供一种更强大的可自定义的认证解决方案.

Memcached安全性

- - xiaobaoqiu Blog
1.Memcached -l参数. 1.Memcached -l参数. 最近整理了组内使用的Memcached. 发现很多问题,其中一个问题就是开发机器测试机器可以直连线上的Memcached. 这也是memcached公认的问题:memcached 是一种很简单、有效的协议,但也有其缺点,就是 memcached 自身没有 ACL 控制(或者相当弱).

sessionId安全性

- - 互联网 - ITeye博客
session id 安全性问题. 最一般的方法是自己管理session id. 用户login后,在后台加密出一个accessToken,并返回给用户. 客户端接收到accessToken,可以将它存起来,web的话可以存在session storage,手机也可以保存accessToken,用于单点登录.

HTML 安全列表

- 火锅土豆 - 酷壳 - CoolShell.cn
下面这个网站罗列了,几乎所有的关于HTML 5 在各种主流浏览器上的安全问题,这些安全问题很有可能将会是黑客攻击你的网上的敲门砖,他们几乎都和Javascript都有关系,你就要好好注意了. IE6,7,8,9,和Opera 8.x, 9.x, 10.x 都支持这样的语法. 这个问题会存在于所有的Firefox版本中,可以让用户进行XSS(跨站脚本)攻击.