Google Authenticator,谷歌身份认证器,Google公司推出的一款动态口令工具,旨在解
决大家Google账户遭到恶意攻击的问题。该工具主要基于TOTP(Time-Based One-Time Password
,基于时间的一次性密码)算法。


需求:攻击者在通过某种方式持有了用户的用户名和密码组合,就可以登录用户账户并进行
操作。为了增强用户账户安全性,保护用户数据不被获取和利用,产生了该身份认证机制。

 
使用场景描述:用户持有一部安装有客户端的移动设备,服务器端验证用户账户信息,确认
用户身份后允许用户登录。客户端输入了用户的账户名、密码后,还需要客户端生成一个随
时间变化的一次性动态口令并要求用户输入,发送给服务器。服务器接收到用户输入的信息
后,在验证用户名、密码的基础上,再计算自己的动态口令值并和用户数据对比,匹配成功
后允许用户登录成功,否则失败。

以下为该机制的原理分析:
(1)HOTP算法分析。Google Authenticator机制主要基于TOTP算法来实现的,而TOTP算法
本身是基于HOTP(HMAC-based One-Time Password,一种基于HMAC的一次性口令算法)算法
改进的。算法核心内容包括三个参数:一个双方共享的密钥(一个比特序列)K,用于一次
性密码的生成;双方各持有一个计数器C,并且实现将计数值同步;一个签署函数即如下公
式:HOTP(K,C) = Truncate(HMAC-SHA-1(K,C)),上面使用了HMAC-SHA-1,也可以使用HMAC-MD5
等。简单步骤如下:
1、客户端利用持有的密钥K和计数器数值C,通过上述算法公式生成HOTP值,同时计数器值
加1,然后要求用户输入该HOTP值,然后客户端将用户名、密码,连同生成的HOTP值发送给
服务器;
2、服务器获取到客户端发送的信息,解析并验证用户名、密码,然后服务器利用持有的密
钥及自身的计数器数值C,通过相同的算法生成HOTP值,再与客户端的HOTP值对比,如果成
功,则计数器值加1,并允许该客户端登录用户账户,否则拒绝登录。

算法存在的问题:客户端每次请求生成一次性密码操作都会使得计数器值加1,而同时如果
验证失败或者客户端不小心多进行了一次生成密码操作,那么服务器和客户端之间的计数器
C将不再同步,因此需要有一个重新同步(Resynchronization)的机制。由于该重同步机制
对于TOTP算法分析没有太多帮助,因此在此不再赘述,需要了解重同步机制详细的,请参看
RFC4226。

(2)TOTP算法分析。利用HOTP算法,将其中的计数器C用当前时间T来替代,同样可以得到
随着时间变化的一次性密码,并且减小计数器的代价,毕竟更多的使用场景中获取系统时间
是方便的。TOTP算法的三个核心内容也容易理解了:共享密钥K;客户端与服务器的时间同
步;签署函数TOTP = Truncate(HMAC-SHA-1(K, (T - T0) / X)),其中T0是Unix epoch(1970
年1月1日 00:00:00),X为时间分片长度。算法执行流程大致如HOTP算法,不再赘述,不同
的是,本算法中用系统时间T代替了计数器数值C作为HMAC算法的输入。

 需要注意的有几点:1、HMAC算法得出的值位数比较多,不方便用户输入,因此需要截断
 (Truncate)成一组不太长的是进制数(至少6位)2、由于时间是一直动态变化的,这就导
致服务器接收到客户端的消息,再进行TOTP值的计算时,时间上会有延时。因此,需要将时
间划片,当然,时间划片要合理,过短导致用户来不及输入并传输给服务器验证,过长导致
攻击者有足够的时间对用户账户进行攻击。Google默认的采用30秒时间分片,即每过三十秒,
系统时间T的值就会发生变化,得到的动态口令也不相同。3、同样利用系统时间的TOTP算法
也是需要重同步机制。由于网络延时、用户输入延迟等因素,可能服务器端接收到一次性密
码时,T数值已经发生了变化,这样就会导致验证失败。解决方法是,服务器计算当前时间
片以及前面的n个时间片内的TOTP值,只要其中有一个与用户输入的TOTP值相同,则验证通
过。同时也容易理解,n不能设置过大,否则将会降低安全性。该方法还有另外的功能,有
时候客户端与服务器的时钟会有偏差,这样也会造成上面类似的问题。但是如果服务器通过
计算前n个时间片的密码并且成功验证之后,服务器就知道了客户端的时钟偏差。因此,下
一次验证时,服务器就可以直接将偏差考虑在内进行计算,而不需要进行n次计算。

关于文中HOTP算法公式和TOTP算法公式的详细实现,也可以参看RFC4226,其中对于算法通
用性的考虑而做的改进值得学习。

 
值得一提的是,由于利用了系统时间,在一般情况下,生成该动态口令内嵌与程序中,本身
是无需联网的,并且系统时间普遍存在于各个设备中,算法通用性良好。

 一些总结:
1、无论是HOTP还是TOTP算法,都存在重同步问题。参考RFC4226可知,在前者的计数器C
重同步问题中,客户端计数器的值可以预料到必然大于服务器计数器的值,在验证过程中,
服务器向后计算N个HOTP值用来匹配一个客户端HOTP值,验证并通过。至于后者,TOTP
算法要求客户端与服务器时间同步,并且服务器计算TOTP值时会向前计算N个TOTP值用来
匹配一个客户端的TOTP值,从而保证了重同步。这是二者重同步问题中的区别。

2、由于上述的重同步方式,相对也会造成一定的系统安全性问题。同样参考RFC4226,
两种方式的系统服务器端,都会给服务器检测HOTP/TOTP值设置一个阀值S,用来保证服务
器不会不停的检测数值,从而限制了试图制造HOTP/TOTP值的攻击者的可能空间。