在像互联网一样复杂的生态系统中升级安全协议是困难的。您需要更新客户端和服务器,并确保它们之间的所有内容都能继续正常工作。互联网正在进行这样的升级。传输层安全性(TLS)是一种使网页浏览保密的协议(许多人持续致电SSL)正在通过引入TLS 1.3进行第一次重大改进。去年,Cloudflare是第一个在服务器端默认支持TLS 1.3的主要提供商。我们预计客户端将会跟随并随后在所有主流浏览器中启用。自从Cloudflare的TLS 1.3发布以来,已经有一年多的时间了,而且目前还没有任何主流浏览器默认启用TLS 1.3。
为什么还没有部署TLS 1.3的还原答案是中间件(middlebox):网络设备,旨在监视并有时拦截企业环境和移动网络中的HTTPS流量。这些middlebox中的一些错误地实现了TLS 1.2,现在阻止浏览器发布TLS 1.3。但是,简单地指责网络设备供应商将是不诚实的。更深层次的事实是,TLS 1.3最初的设计与互联网随着时间推移而发展的方式是不相容的。如何以及为什么发生这是我将在这篇博客文章中探讨的多方面的问题。
为了帮助支持与数据的讨论,我们构建了一个工具来帮助检查您的网络是否与TLS 1.3兼容:https:
//tls13.mitm.watch/
如何使用版本协商在TLS中工作
传输层安全协议TLS是支持使用HTTPS进行安全Web浏览的重要手段。在20世纪90年代后期,TLS协议从较早的协议,即安全套接字层(SSL)改编而来。TLS目前有三个版本:1.0,1.1和1.2。该协议是非常灵活的,可以随着时间的推移以不同的方式演变。可以将小的更改作为“扩展”(例如OCSP和证书透明度)来合并,而更大和更基本的更改通常需要新版本。TLS 1.3是迄今为止协议历史上最大的变化,彻底改造了密码学,并引入了像0-RTT这样的特性。
并非每个客户端和服务器都支持相同版本的TLS,因此不可能升级协议,因此大多数同时支持多个版本。为了就连接的通用版本达成一致,客户端和服务器进行协商。TLS版本的协商非常简单。客户端通知服务器它支持的协议的最新版本,服务器回复它们都支持的协议的最新版本。
TLS中的版本以双字节值表示。由于TLS是从SSLv3改编的,协议中使用的字面版本号只是次要版本的增量:
SSLv3是3.0
TLS 1.0是3.1
TLS 1.1是3.2
TLS 1.2是3.3等
使用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和降级舞蹈
CC0知识共享
TLS的最后一次重大升级是引入了TLS 1.2。在浏览器中部署TLS 1.2的过程中,发现一些TLS 1.0服务器没有正确实现版本协商。当客户端连接到TLS 1.2的TLS连接广告支持时,有故障的服务器将断开连接,而不是协商他们理解的TLS版本(如TLS 1.0)。
浏览器有三个选项来处理这种情况
启用TLS 1.2和一些网站将停止工作
延迟TLS 1.2的部署,直到这些服务器被修复
如果连接失败,请重试旧版本的TLS
人们对他们的浏览器的期望是,当他们更新时,网站继续工作。行为不当的服务器数量太多,不能与更新相冲突,因此不能选择1)。从这一点来看,TLS 1.2已经存在了一年多了,而且服务器还在等待更长时间并不能解决这个问题,所以没有选择2)。这留下选项3)是唯一可行的选择。
为了启用TLS 1.2并保持用户满意,大多数浏览器实现了所谓的“不安全的降级”。当连接到站点时遇到连接失败时,他们将再次尝试使用TLS 1.1,然后使用TLS 1.0,如果失败,则使用SSLv3。这降级逻辑“固定”这些破碎的服务器...在一个缓慢的连接建立的代价。
然而,不安全的降级被称为不安全的原因。客户端降级是由特定类型的网络故障触发的,可能很容易被欺骗。从客户的角度来看,无法判断这个故障是由服务器故障还是由正好处于连接网络路径上的攻击者造成的。这意味着网络攻击者可以注入假的网络故障,并欺骗客户端连接到SSLv3的服务器,即使两者都支持更新的协议。在这一点上,SSLv3没有严重的公开漏洞,所以这看起来不是一个大问题。然后POODLE发生了。
2014年10月,BodoMöller发布了POODLE,这是SSLv3协议中的一个严重漏洞,允许网络内部的攻击者以最小的努力显示加密的信息。由于TLS 1.0在客户端和服务器上都被广泛部署,网络上很少有连接使用SSLv3,这应该保证它们的安全。然而,不安全的降级功能使得攻击者可以降级到SSLv3的任何连接,如果双方都支持的话(大部分都是这样)。这种“降级舞蹈”矢量的可用性将POODLE所带来的风险从好奇心转变为影响大多数网络的严重问题。
修复POODLE并删除不安全的降级
POODLE的修复程序是:
禁用客户端或服务器上的SSLv3
启用称为SCSV的新的TLS功能。
在POODLE之前的几个月,SCSV由BodoMöller和Adam Langley提出。简而言之,如果由于网络错误而重试,客户端通过SCSV将名为“ 降级金丝雀”的指标添加到客户端hello消息中。如果服务器支持比在客户端hello中发布的版本更新的版本,并且看到这个金丝雀,它可以假设正在发生降级攻击并关闭连接。这是一个很好的功能,但它是可选的,需要更新客户端和服务器,从而使许多Web用户暴露。
浏览器立即删除了对SSLv3的支持,除了打破一些只有SSLv3的网站之外,几乎没有什么影响。使用旧浏览器的用户必须依赖禁用SSLv3的Web服务器。Cloudflare 立即为客户做到了这一点,大多数网站也是如此,但即使在2017年末,SSL Pulse测量的网站中仍有超过10%仍然支持SSLv3。
关闭SSLv3对于POODLE来说是一个可行的解决方案,因为SSLv3对于Internet来说并不重要。这引出了一个问题:如果TLS 1.0存在严重的漏洞,会发生什么?TLS 1.0仍然是非常广泛的使用和依赖,在浏览器中关闭它将锁定大约10%的用户。而且,尽管SCSV是不安全的降级的一个很好的解决方案,许多服务器不支持它。确保用户对TLS 1.0将来问题的安全性的唯一选择是禁用不安全的回退。
由于客户端不得不重新连接多次,经过多年的不良表现,大部分没有实现版本协商的网站都正确地固定了服务器。这使得一些浏览器可以消除这种不安全的后备:
2015年的Firefox和2016年的Chrome https://developers.google.com/web/updates/2016/03/chrome-50-deprecations#remove insecure tls 版本后备]。因此,如果发生新的TLS 1.0漏洞,Chrome和Firefox用户现在处于更安全的位置。
介绍新版本(再次)
为未来的兼容性设计协议是困难的,如果没有反馈机制,很容易出错。这是TLS版本协商的情况:如果实施错误,只是假设的未来版本,没有什么可以中断的。对开发者来说,没有任何信号给实施者是有缺陷的,所以错误可能会在没有被注意的情况下发生。也就是说,直到部署了一个新版本的协议,并且实现失败,但是到了代码部署之后,每个人都需要花费数年的时间进行升级。一些服务器实现未能正确处理“未来”版本的TLS的事实应该是预料之中的事实。
TLS版本协商虽然很简单,但实际上是协议设计反模式的一个例子。它证明了协议设计中称为骨化的现象。如果一个协议被设计成一个灵活的结构,但实际上从来没有使用这种灵活性,那么一些实现将假定它是不变的。亚当兰利比较现象生锈。如果你很少打开门,它的铰链更容易生锈。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。HannoBöck,David Benjamin,SSL Labs和其他人进行的互联网扫描证实,TLS 1.3的失败率很高,在许多测量中超过3%。这与升级到TLS 1.2时所面临的情况完全相同。历史正在重演。
这个意想不到的挫折给参与协议设计的人们带来了种种危机。浏览者不希望重新启用这种不安全的降级,并且为了在接下来的五年中再次加强协议谈判而进行艰苦的斗争。但是,如果没有降级,使用TLS 1.3将会为用户打破3%的互联网。可以做什么?
有争议的选择是接受David Benjamin的建议,使第一个TLS 1.3消息(客户问候)看起来像TLS 1.2。客户端的版本号被重新改回(3,3),并引入了一个新的“版本”扩展,其中包含了受支持版本的列表。如果支持TLS 1.3和(3,3),则服务器将返回以(3,4)开始的服务器hello,否则返回前面的值。TLS 1.3草案16包含了这个新的和“改进的”协议协商逻辑。
这工作。大部分服务器都可以容忍这个变化,而且很容易回到TLS 1.2,忽略了新的扩展。但这不是故事的结尾。骨化是一个反复无常的现象。它不仅影响客户端和服务器,还会影响网络上与协议交互的所有内容。
现实世界充满了中间件
CC BY-SA 3.0
我们博客的读者可能会记得今年早些时候有关HTTPS拦截的帖子。其中,我们讨论了一项研究,测量了浏览器和Web服务器之间的检测软件或硬件实际拦截和解密了多少“安全”HTTPS连接。还有一些被动的检查中间件解析TLS,并根据可见数据阻止或转移连接,如使用来自TLS连接的主机名信息(SNI)的ISP 来阻止“禁止”网站。
为了检查流量,这些网络设备需要实施部分或全部TLS。每个支持TLS的新设备都引入了一个TLS实现,该实现假设协议应该如何操作。有更多的实现,骨化发生的可能性就越大。
在2017年2月,Chrome和Firefox都开始为其客户提供TLS 1.3。结果出乎意料的糟糕。TLS 1.3连接的百分比远高于预期。对于一些用户来说,不管网站是什么,TLS 1.2工作,但TLS 1.3没有。
TLS 1.3草案18的成功率
Firefox & Cloudflare 97.8% for TLS 1.2 96.1% for TLS 1.3Chrome & Gmail 98.3% for TLS 1.2 92.3% for TLS 1.3
经过一番调查,发现一些广泛部署的中间件,无论是截取和被动类型,都造成连接失败。
由于TLS在整个历史中看起来大致相同,因此一些网络设备对协议如何随着时间的推移作出了假设。面对违反这些假设的新版本时,这些设备会以各种方式出现故障。
在TLS 1.3中更改的TLS的一些功能仅仅是表面上的。像SSLv3以来,协议中的ChangeCipherSpec,session_id和压缩字段被删除。这些领域被认为是TLS对这些中间件的一些基本特征,并且消除它们导致连接失败。
如果一个协议被使用足够长的时间并且格式足够类似,那么围绕该协议构建工具的人将会假设这个格式是不变的。这通常不是开发者的有意选择,而是实践中如何使用协议的意想不到的结果。网络设备的开发人员可能不了解互联网上使用的每一种协议,所以他们经常测试他们在网络上看到的东西。如果一个被认为是灵活的协议的一部分在实践中不会改变,有人会认为它是一个常量。这更可能是更多的实现创建。
把这一切归咎于这些中间件的具体实现者是不诚实的。是的,他们创建了TLS的错误实现,但另一种思考的方式是TLS的原始设计使自己陷入了这种类型的失败。实现者按照协议的实际实现,而不是协议设计者的意图或规范的文本。在具有多个实施者的复杂生态系统中,未使用的接头会生锈。
去除20年来一直是协议一部分的功能,并期望它只是“工作”是一厢情愿的想法。
使TLS 1.3工作
上个月在新加坡举行的IETF会议上,TLS 1.3提出了一个新的改变来帮助解决这个问题。这些变化是基于来自Facebook的Kyle Nekritz的想法:使TLS 1.3看起来像TLS 1.2到middleboxes。这个改变重新引入了被删除的协议中的很多部分(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,将版本协商转移到扩展。作为客户端和服务器之间的中介,middleboxes也关心服务器hello消息。这个信息有更多的灵活性,但被认为是灵活的,但是却没有。几乎所有这些都生锈了。新的“中间箱友好”的变化考虑到了这个现实。这些实验性修改已纳入TLS 1.3草案22中的规范。
确保这不会再发生
原协议谈判机制是无法恢复的燃烧。这意味着它可能不能用于未来版本的TLS,而不会有明显的中断。但是,其他许多协议协商功能仍然是灵活的,例如密码组选择和扩展。保持这种方式将是非常好的。
去年,Adam Langley写了一篇关于加密协议设计的好博客文章(https://www.imperialviolet.org/2016/05/16/agility.html),其内容与本博文相似。在他的文章中,他提出了“有一个联合,保持良好的润滑”的格言。这对于协议设计者来说是一个很好的建议。正如我们在TLS 1.3中看到的,骨化是真实的。
大卫·本杰明(David Benjamin)提出了一种方法来保持油中TLS中最重要的关节。他对GRE的GREASE提案是为了在协议应该容忍新值的情况下抛出随机值。如果流行的实现在现实世界的部署中散布未知的密码,扩展和版本,那么实现者将被迫正确地处理它们。GREASE就像互联网上的WD-40一样。
有一点需要注意的是,GREASE的目的是防止服务器僵化,而不是中间件,所以在TLS中仍然有更多类型的加脂的可能性。
即使使用GREASE,一些服务器也只能在2017年12月才被发现对TLS 1.3不能容忍.GREASE只能识别不能识别未知扩展的服务器,但是某些服务器可能仍然不能容忍特定的扩展ID。例如,RSA的BSAFE库使用扩展名为40的名为“extended_random”的实验扩展,与理论化的NSA后门相关联。分机ID 40恰好是用于TLS 1.3密钥共享的扩展ID。大卫·本杰明(David Benjamin)报告说,这个库仍然被一些打印机所使用,导致它们不能使用TLS 1.3。马修·格林对此兼容性问题进行了详细的介绍。
帮助我们理解这个问题
Cloudflare一直在与Mozilla Firefox团队合作来帮助衡量这一现象,Google和Facebook一直在做他们自己的测量。这些实验很难执行,因为开发人员需要将协议变体添加到浏览器中,这可能需要浏览器的整个发布周期(通常几个月)才能看到问题的用户。Cloudflare现在支持最新的(有希望的)中间件兼容的TLS 1.3草案版本(草案22),但总有一个机会,我们找到一个与这个版本不兼容的中间件。
为了避开浏览器发布周期,我们采取了一条捷径。我们建立了一个网站,您可以使用它来查看TLS 1.3是否在浏览器的有利位置运行。这个测试是由我们的Crypto实习生Peter Wu建立的。它使用Adobe Flash,因为这是从浏览器访问原始套接字的唯一广泛的跨平台方式。
怎么运行的:
我们将基于Golang的TLS 1.3客户端库(tls-tris)交叉编译为JavaScript
我们构建一个JavaScript库(称为jssock),在通过Adobe Flash公开的底层套接字接口网络上实现tls-tris
我们使用TLS 1.2和TLS 1.3连接到远程服务器,并比较结果
如果出现不匹配的情况,我们会从双方的连接处收集信息并将其发送回来进行分析
如果你看到一个失败,让我们知道!如果您处于公司环境中,请分享中间件信息,如果您在住宅网络中,请告诉我们您的ISP是谁。
我们很高兴TLS 1.3最终在浏览器中默认启用。这个实验将有助于证明最新的变化使用户可以安全升级。