导语:在上一篇文章中,我对U2F设备的各种安全密钥进行了一个很粗浅的安全介绍,这其中就包括了:基本功能,物理特征等,如果你感兴趣可以点此了解详情。在今天的这篇文章中,我会从一个更低级别的特征来测试U2F设备的安全性。

560e41934dd1a.jpg

在上一篇文章中,我对U2F设备的各种安全密钥进行了一个很粗浅的安全介绍,这其中就包括了:基本功能,物理特征等,如果你感兴趣可以点此了解详情。在今天的这篇文章中,我会从一个更低级别的特征来测试U2F设备的安全性。

安全密钥用的是FIDO U2F规范,U2F (Universal 2nd Factor) 是 Yubico, Yahoo 和 Google 联合开发的基于物理设备的双因素认证协议,目前已经完成标准化,从属于 FIDO (Fast Identity Online) 联盟名下。另外,FIDO U2F规范借鉴了智能卡ISO7816-4规范中的许多标准。FIDO U2F尽可能对每种可能的传输(USB,NFC或蓝牙)都进行规范,已确定它们在传输时是如何封装U2F消息的,例如,USB接口会如何封装U2F消息。 目前FIDO正在对目前的标准进行修订,以应对未来可能的情况,不过目前所有的安全密钥标准都实现了基本的安全功能。简而言之,U2F包含三大部分:注册,验证和检查。

注册时U2F设备会创建一个新的密钥对,更准确地说,注册时服务器会产生一个32字节的Challenge数据和一个32字节的应用id。

注册请求消息有两部分,如下图所示:

360截图164003048690137.jpg

challenge parameter[32 bytes], challenge parameter是对客户端数据进行SHA-256运算得到的哈希值,另外Challenge是一个随机数。Client Data是一个由FIDO客户端准备的JSON数据结构。

application parameter[32 bytes],application parameter是请求注册的应用id的SHA-256结果。而对于浏览器,应用id是登录页面的起始地址中的URL的哈希值。

U2F设备的密钥对

U2F设备产生的密钥对是服务器关联的,一对密钥对应一个服务器,而不是一个U2F设备对应一个服务器。在注册的时候,服务器给U2F设备传入服务器相关信息,U2F设备产生一对密钥对,将此密钥对和服务器相关信息相关联,给此密钥对分配一个key handle,将其和公钥传给服务器,服务器将注册的账户信息,公钥,key handle全部关联在一起并保存。

当用户需要使用U2F验证操作时,服务器产生Challenge数据,使用U2F设备做签名,此时服务器将key Handle和服务器信息通过浏览器传给U2F设备,U2F设备使用Key Handle,寻找对应的密钥对,如果密钥对存在,检验密钥对应的服务器信息是否和传入的服务器信息匹配,如果不匹配,说明服务器是伪造或者不正确的。如果正确,U2F设备等待用户按键确认,用户按键后,U2F设备对Challenge数据做签名,应用id返回给服务器,服务器验证应用id,如果签名正确,说明此公钥对应的唯一私钥是正确的,表明用户拥有合法的U2F设备,如果签名不正确,说明此用户正在伪造身份登录。

U2F设备安全特性

然而一个比较有趣的地方是,U2F设备不带无穷大的安全存储空间。在实际研究过程中,我发现key handle实际上是一个加密的私钥,即用令牌卸载存储的私有密钥。然而,从理论上讲,key handle可能只是一个整数,用于对令牌内的存储密钥进行索引。所以为了保证安全性,私钥的保护很重要。U2F协议允许一个廉价的设备,同时保证此设备不会泄露私钥。Key handle可以不是U2F设备上一个私钥的索引,相反,Key Handle可以用来存储私钥和服务器相关信息,这些信息可以被加密保存到一个Key Handle中(例如使用aes加密私钥和服务器数据)。

鉴于此,在新修订的FIDO U2F规范中,有许多关键的安全规范还是应该保留下来,比如:

1.Key Handle应加密,以防止在那里找到ECDSA私钥。
2.一个安全密钥的Key Handle不能与另一个安全密钥一起使用,即使是相同的类型。
3.如果一个安全密钥被要求生成数百个密钥对,那么它们都应该是不同的。
4.所有的签名都应该有唯一的随机数,否则就可能出现安全漏洞,让人提取你的私钥。
5.应该对应用id进行检查。

但除此之外,还有其他一些安全性需要进行测试:

1.Key Handle是否是U2F令牌产生的,如果U2F令牌发现key handle不是自己创建的,直接进行错误返回,如果是,U2F令牌必须返回一个认证响应。
2.签名是否被正确编码了?U2F设备的签名采用的是ASN.1编码。
3.USB协议传输的是64字节数据包,最后的填充字节应全部为零,而不是随机的内存字节。

给了这么多理论的安全建议,但最终还是要理论结合实践,下面就让我们看看目前市场上的U2F设备是如何进行密钥管理的。

Yubico

Yubico的产品目前还处于比较领先的位置,产品还暂时没有发现什么漏洞,必定U2F的标准就是Yubico牵头制定的。

Vasco公司的SecureClick

Vasco公司的SecureClick也是一款很不错的产品,具体介绍点此https://github.com/hillbrad/U2FReviews#secureclick。这是一个蓝牙低功耗(BLE)令牌,这意味着它可以与Android和iOS设备配合使用。对于非移动设备,它包括一个USB-A BLE加密狗。 SecureClick使用Chrome扩展来配置和配对跨平台的加密狗。加密狗看起来像一个普通的USB设备,但区别就是它能从令牌中检测到到一个BLE信号,此时它会“断开”,并进行重新连接,以执行U2F操作。一旦需要用户注册或认证的操作完成,则令牌就会自动断电,并且加密狗再次断开并重新恢复到原始USB设备的状态。

如果你正在使用Linux,那配置的udev(设备管理器)就可以正常显示令牌供应商的ID和产品ID的访问权限,不过由于供应商ID和产品ID是不同的,所以令牌无法正常工作, Chrome扩展程序也很混乱。还有一个问题就是BLE令牌设备的电池经常会因电量耗尽而停止工作。 

飞天诚信的ePass

ePass系列是由飞天诚信公司推出USB Key,主要是用作基于公钥体系的数字证书和私钥的安全载体,大小如同房间钥匙,形状和市面上的U盘相像,可以穿在钥匙环上随身携带。目前飞天诚信已获FIDO UAF认证,成为国内唯一一家拥有U2F和UAF双证的企业

ASN.1 DER被设计为可辨别的编码,即对于给定值,应该进行唯一的排列,这样所有其他表示都是无效的。因此,数字应该被最小化编码,没有前导零。

不过ePass并不具备这样的安全密钥,因为从9个前导零位开始的数字在开始时都有一个无效的零字节。可以推测,从17个零位开始的数字在开始时都有两个无效的零字节,但是我没有足够的时间来寻找具体的案例。不过我可以推测这种安全密钥生成的256个签名中,只有一个属于无效编码。

此外,Key Handle的最后八个字节似乎是多余的,也就是说,你可以将它们更改为你喜欢的任何值,至于是否能起到安全密钥就不一定了。其实这倒不是什么问题,真正的问题是,它们是否会被使用?另外,USB数据包中的填充数据不为零,不过这只是显然了传输缓冲区的以前内容,并不会泄露什么敏感数据。

Thetis

不知是什么原因,我无法在此设备上测试一些安全特性,比如Key Handle的可变性,应用id是否经过了检查等。对Key Handle的可变性检查的响应是无效的,根据FIDO U2F规范,检查响应的返回状态为0x9000 (“NO_ERROR”),但其实返回状态应该为0x6985或0x6a80。之后,它开始拒绝所有的含有0x6a80的Key Handle(包括有效的)的响应。

该设备具有与飞天诚信的ePass相同的非最小签名编码问题,此外,如果你按键的速度太快,这个安全密钥就会陷入混乱并拒绝一些status 0x6ffe请求。另外,USB填充字节也不为零。

U2F Zero

1KiB ping消息崩溃此设备(即它停止响应USB消息,需要拔下并重新插入)。测试一个损坏的钥匙柄也会崩溃,因此我无法运行许多测试。

一个1KiB的 ping消息即会让U2F Zero崩溃,并停止响应任何USB消息,如果要重新运行就要拔下来重新插入。另外测试一个崩溃的Key Handle也会崩溃,所以最后我只能放弃对其的安全性测试。

KEY-ID/HyperFIDO

Key-ID和HyperFIDO设备,具有相同的固件,它们具有与ePass相同的非最小编码问题,除此之外,还存在ASN.1缺陷。在ASN.1 DER中,如果一个数字的最高有效位被设置,那该数字就是负数。如果不是负数,则需要一个零填充字节。当测试最高有效位时安全密钥会检查第一个字节是否是> 0x80,但按照规范应该检查第一个字节是否是>= 0x80。这样检查的结果就是有时会产生含有负数的签名,使得检查无效。

另外,USB填充字节不是零,而且还包括了不属于请求或响应的一部分数据。虽然这些数据不太可能有什么实质的影响,但它们是从哪里来的呢?这个确实是个有待研究的问题。

还有就是封装的密钥也有一些问题。首先,字节16到31是设备和应用id的函数,因此,在不同的帐户使用时,给定站点可以被动地识别到相同的标记。字节48至79未经身份验证,并且在更改时,除了签名错误之外,所有内容仍然有效,这表明这些字节就是加密的私钥或生成它的加密种子。最后,虽然字节32到47不能被任意操作,但是可以用来自不同的key handle的替换相同的字节,这就会导致签名错误。

源链接

Hacking more

...