导语
面对日益猖獗的黑客攻击,许多沿用多年的网络安全标准也面临着被替换或更新的命运。TLS是目前网络通信中应用最广泛的密码协议,TLS1.2是目前最常用的TLS版本,主要用于保护通过HTTPs传输的信息,为各种应用提供安全的通信信道。
比如电子货币交易、邮件传输、VPN以及手机安卓应用等等。不过由于漏洞过多,且TLS的应用规模过于庞大,不断地在大规模的应用中修修补补显然达不到很好的防御效果。除此之外,交互双方必须运行复杂的TLS握手协议才能开始传输信息,很多情况下我们希望在握手轮数和握手延迟方面可以有更多的选择。出于以上以及其他种种因素的考虑,IETF从2014年就着手制定TLS 1.3。TLS 1.3延续了TLS 1.0、1.1和1.2的名称,这说明它是之前版本的升级,TLS协议的大致框架并未发生本质改变。不过,TLS 1.3是TLS标准更新过程中变动最大的一次,除了对运行过程中的若干问题如密码套件的选择、密钥的计算方式、握手消息的发送方式等做了更改之外,TLS 1.3还增加了新的握手模式,以满足不同应用场景的需求。
升级安全协议所面对的困难
在像互联网一样复杂的生态系统中升级安全协议是困难的,你需要更新客户端和服务器,并确保它们连接起来都能继续正常工作。2016年,Cloudflare是第一个在服务器端默认支持TLS 1.3的供应商。自从Cloudflare的TLS 1.3发布以来,已经有一年多的时间了,但是仍然没有一个主流的浏览器默认启用TLS 1.3。
其主要的原因是因为中间件(middlebox):网络设备,该设备会被用于监视并拦截企业环境和移动网络中的HTTPS流量。但是,简单地把责任归咎于网络设备供应商是不客观的的。更深层次的事实是,TLS 1.3最初的设计没有考虑到互联网应用的飞速发展。本文,我会构建了一个工具来帮助检查你的网络是否与TLS 1.3兼容。
TLS的演化过程
传输层安全协议TLS是支持使用HTTPS进行安全Web浏览的重要手段,在20世纪90年代后期,TLS协议从较早的协议,即安全套接字层(SSL)改编而来。TLS目前有三个版本:1.0,1.1和1.2。该协议是非常灵活的,可以随着时间的推移以不同的方式演变。较小的更改可以被合并为“扩展”(例如OCSP和证书透明度),而更大和更基本的更改通常需要新版本。TLS 1.3是迄今为止协议历史上最大的变化,彻底修改了加密技术,并引入了像0-RTT这样的特性。
并非所有的客户端和服务器都支持相同版本的TLS,因此不可能升级协议,因此大多数都同时支持多个版本。为了就连接的通用版本达成一致,客户端和服务器会进行协商。TLS版本的协商非常简单。客户端会通知服务器它支持的协议的最新版本,服务器则会回复它们都支持的协议的最新版本。
使用TLS连接到服务器时,客户端会在连接开始时发送其支持的最高版本:
(3, 3) → server
一个理解相同版本的服务器可以以相同的版本字节开始回复:
(3, 3) → serverclient ← (3, 3)
如果服务器只知道该协议的旧版本,则可以使用旧版本进行回复。例如,如果服务器只说TLS 1.0,则可以回复:
(3, 3) → serverclient ← (3, 1)
如果客户端支持服务器返回的版本,则他们就可以继续使用该版本的TLS并建立安全连接。如果客户端和服务器不共享通用版本,则连接失败。
这次协商的目的是为了与未来版本兼容,如果客户端发送的版本高于服务器支持的版本,服务器应该仍然能够回复服务器支持的任何版本。例如,如果客户端发送(3,8)到TLS 1.2的服务器,它应该只回复(3,3),握手将继续作为TLS 1.2。
虽然很简单,但事实证明,并没有正确地实现这一功能,从而导致的一连串事件,让网络用户面临严重的安全漏洞威胁。
poodle漏洞的出现和不安全的降级
TLS的最后一次大升级是引入了TLS 1.2,在浏览器中部署TLS 1.2的过程中,安全人员发现一些TLS 1.0服务器没有正确实现版本协商。当客户端连接到TLS 1.2的TLS连接广告支持时,有故障的服务器将断开连接,而不是协商他们理解的TLS版本(如TLS 1.0)。
浏览器有三个选项来处理这种情况:
1.启用TLS 1.2,并关闭一些网站;
2.延迟TLS 1.2的部署,直到这些服务器被修复;
3.如果连接失败,则重试旧版本的TLS。
一般情况下,用户认为,浏览器更新后,并不会影响网站的运行。由于目前协商不当的服务器数量太多,所以选项3是唯一可行的选择。
为了启用TLS 1.2并保持用户满意,大多数浏览器实现了所谓的“不安全的降级(insecure downgrade)”。当连接到站点时遇到连接失败时,他们将再次尝试使用TLS 1.1,然后使用TLS 1.0,如果失败,则使用SSLv3。这种降级逻辑虽然让这些损坏的服务器暂时看起来被“修复”,其实只是积压了问题而已。
之所以,不安全的降级会被称为不安全,是因为客户端降级是由特定类型的网络故障触发的,可能很容易被欺骗。从客户的角度来看,无法判断这个故障是由服务器故障还是由正好处于连接网络路径上的攻击者造成的。这意味着网络攻击者可以注入假的网络故障,并欺骗客户端连接到SSLv3的服务器,即使两者都支持更新的协议。此时,SSLv3看起来还没有严重的公开漏洞,不过,poodle漏洞的出现改变了这个看法。
2014年,POODLE(Padding Oracle On Downgraded Legacy Encryption)漏洞曾影响了使用最广泛的加密标准——SSL v3.0,攻击者可以利用该漏洞发动中间人攻击拦截用户浏览器和HTTPS站点的流量,然后窃取用户的敏感信息,如用户认证的cookies信息、账号信息等。
由于TLS 1.0在客户端和服务器上都被广泛部署,网络上很少有连接使用SSLv3,理论上,这应该保证它们的安全。然而,如果双方都支持的话(大部分都是这样),这种不安全的降级特点使得攻击者可以将任何连接降级到SSLv3,从而形成一个大漏洞。
修复POODLE以及删除不安全的降级所带来的启发
POODLE的修复过程如下:
1.禁用客户端或服务器上的SSLv3;
2.启用称为SCSV的新的TLS功能。
在POODLE漏洞发生的前的几个月,SCSV就由BodoMöller和Adam Langley提出。简而言之,如果由于网络错误而重试,客户端就会通过SCSV将名为“downgrade canary”的指标添加到客户端hello消息中。如果服务器支持比在客户端hello中发布的版本更新的版本,并且看到这个“downgrade canary”指标,它可以假定降级攻击正在发生并关闭连接。这是一个很好的功能,但它是个可选项,需要更新客户端和服务器。
删除了浏览器对SSLv3的支持,除了影响一些只用SSLv3的网站之外,几乎没有什么影响。使用旧浏览器的用户必须依赖禁用SSLv3的Web服务器, Cloudflare可以立即为客户做到了这一点,大多数网站也是如此,但即使在2017年末,SSL Pulse测量的网站中仍有超过10%仍然支持SSLv3。
关闭SSLv3对于POODLE来说是一个可行的解决方案,因为SSLv3对于互联网来说并不重要。这就产生了一个问题:如果TLS 1.0存在严重漏洞,会发生什么? 目前,TLS 1.0的使用仍然是非常广泛,在浏览器中关闭它将影响大约10%的网络用户。而且,尽管SCSV是不安全降级的一个很好的解决方案,但许多服务器还是不支持它。
TLS 1.3的介绍
为未来的兼容性设计协议是困难的,如果没有反馈机制,很容易出错。TLS版本协商虽然很简单,但实际上是协议设计的一个反面模式。在TLS 1.2部署的时候,围绕着设计一个雄心勃勃的新版TLS的讨论正在开始。它将被称为TLS 1.3,版本号自然选为3.4(或(3,4))。到2016年年中,TLS 1.3草案已经经历了15次迭代,基本确定了版本号和协商。在这一点上,浏览器已经消除了不安全的可能。假设无法正确进行TLS版本协商的服务器已经学习了POODLE的教训,并最终正确地实现了版本协商。事实证明,情况并非如此。漏洞再次发生。
当与3.4版本的客户问好时,很大一部分支持TLS 1.2的服务器会断开连接,而不是回复3.3。 经过实际测试证实,TLS 1.3的失败率非常高,在许多测量中超过3%。这与升级到TLS 1.2时所面临的情况完全相同。
这个意想不到的挫折给参与协议设计的人们带来了很大打击,显然,照此下去,浏览者不希望重新启用这种不安全的降级。但是,如果没有降级,使用TLS 1.3将会为用户提高3%的上网风险。
有人曾建议过如下的解决方法:就是使第一个TLS 1.3消息(客户问候)看起来像TLS 1.2。客户端的版本号被重新改回(3,3),并引入了一个新的“版本”扩展,其中包含了受支持版本的列表。如果支持TLS 1.3和(3,3),则服务器将返回以(3,4)开始的服务器hello,否则返回前面的值。 所以,TLS 1.3草案16就包含了这个新的和“改进的”协议协商逻辑。
大部分服务器都可以接受这个变化,并且很容易回到TLS 1.2,从而忽略了新的扩展。但它不仅会影响客户端和服务器,还会影响网络上与协议交互的所有内容。
现实世界充满了中间件
我曾经测量了浏览器和Web服务器之间的检测软件或硬件实际拦截和解密了多少“安全”HTTPS连接。还有一些被动的检查中间件解析TLS,并根据可见数据阻止或转移连接,如使用来自TLS连接的主机名信息(SNI)的ISP来阻止“禁止”网站。
为了检查流量,这些网络设备需要实施部分或全部的TLS,每个支持TLS的新设备都引入了一个TLS实现。
在2017年2月,Chrome和Firefox都开始为其客户提供TLS 1.3。结果出乎意料的糟糕。对于一些用户来说,不管是什么网站,都是TLS 1.2在工作,但TLS 1.3似乎消失了。
经过一番调查,发现一些广泛部署的中间件,无论是拦截式还是被动式,都会造成连接失败。
由于TLS在整个演变历史中看起来大致相同,因此一些网络设备对协议如何随着时间的推移作出了一个提前假设。当遇到违反这些假设的新版本时,这些设备会出现各种方式的故障。
TLS 1.3中更改的TLS的一些功能仅仅是表面上的,自SSLv3被删除后,协议中的ChangeCipherSpec,session_id和压缩字段就都被删除。这些都被认为是TLS对这些中间件的一些基本特征,如果删除它们就会导致连接失败。
如果一个协议在足够长的时间内使用了类似的格式,那么围绕该协议构建工具的人就会假定这种格式是不变的。这通常不是开发人员有意的选择,而是在实践中使用协议的意外结果。网络设备的开发人员很可能不会了解互联网上使用的每一种协议,所以他们经常会选择测试他们在网上看到的常用协议。
如何让TLS 1.3普及
2017年11月在新加坡举行的IETF会议上,TLS 1.3提出了一个新的改变来帮助解决这个问题。这些变化是基于来自Facebook的Kyle Nekritz的想法,即使TLS 1.3看起来像TLS 1.2到中间件。这个改变重新引入了被删除的协议中的很多部分,比如,session_id,ChangeCipherSpec和一个空的压缩字段,这就使得TLS1.3看起来像TLS1.2一样,这对于中间件很重要。
这些变化的几个迭代是由BoringSSL开发的,并已在Chrome上测试了几个月。 Facebook也进行了一些类似的测试,且两个团队的发现都差不多。
Chrome测试的连接成功率:
TLS 1.2 - 98.6%Experimental changes (PR 1091 on Github) - 98.8%
Firefox测试的连接成功率:
TLS 1.2 - 98.42%Experimental changes (PR 1091 on Github) - 98.37%
这些测试表明,这些变化可以将TLS 1.3修改为与中间件兼容。这就导致了草案16的产生,在草案中,标准的研发者将版本协商转移到了扩展。作为客户端和服务器之间的中介,这样中间件也关心服务器hello消息。
去年,Adam Langley写了一篇关于加密协议设计的博客文章,其内容与本文相似,有兴趣的读者可以看一看。
David Benjamin提出了一种方法来保持TLS中最重要的关节,他对GRE的GREASE提案是为了在协议应该容忍新值的情况下抛出随机值。如果流行的实现在真实的部署中插入未知的密码、扩展和版本,那么实现者将被迫正确地处理它们。在互联网上,GREASE就像WD-40一样。
有一点需要注意的是,GREASE旨在防止服务器僵化,而不是中间件,所以在TLS中仍有可能出现更多类型的GREASE。
即使有了GREASE,一些服务器直到2017年12月才被发现无法支持TLS 1.3。GREASE只识别那些不能接受未知扩展的服务器,但有些服务器可能仍然不能容忍特定的扩展id。例如,RSA的BSAFE库使用了扩展id 40作为一个名为“extended_random”的实验性扩展,与一个理论上的美国国家安全局后门联系在一起。扩展id 40恰好是TLS 1.3密钥共享的扩展id。David Benjamin说,一些打印机仍在使用该库,这导致他们无法忍受TLS 1.3。Matthew Green对这个兼容性问题进行了详细的描述。
Google和Facebook一直在做自己的测量。这些实验很难执行,因为开发人员需要将协议变体添加到浏览器中,在几个月的发布周期里测试,让用户有充足的时间发现问题。Cloudflare现在支持最新与middlebox兼容的TLS 1.3草案版本(草案22),相信,在实测中,Cloudflare总有机会找到一个与这个版本不兼容的中间件。