Cloudflare:让SSL重新变得“无聊”

本文由Alessandro Ghedini于2017年12月6日发布在Cloudflare博客,介绍了Cloudflare从OpenSSL转战BoringSSL的过程和心得。

在几个月前,我们迁移了Cloudflare的边缘SSL连接终端栈,转而使用BoringSSL。BoringSSL是谷歌的加密方法和SSL方案,是OpenSSL的一个分支。

我们花了几个月时间来实现它,并保证不给客户的通信带来负面影响。我们在此过程中遇到了一些麻烦,不得不克服一些挑战,但最终,相比几个月前,我们使情况有所改善。

TLS 1.3

我们已经广泛地记录了TLS 1.3。我们的初始TLS 1.3栈需要我们的(基于OpenSSL的)主SSL终端软件将TCP连接切换到一个单独的基于我们的Go加密/tls标准库的系统,该系统是专门为处理TLS 1.3连接而开发出来的。这很好地证明了,我们可以相对安全地向客户群进行推广。

然而,随着时间的推移,这个单独的系统开始让我们的生活变得复杂了:我们需要将大部分与SSL相关的业务逻辑复制到这个新系统中,这引起了一些微小的bug,会弹出错误提示,并且,这使得像Client Auth这样的新功能在客户中的推广变得更加困难。

不过凑巧的是,BoringSSL已经支持TLS 1.3很长时间了(它是最早开始支持这一功能的开源SSL方案之一),所以现在我们所有的边缘SSL通信量(包括TLS 1.3连接)都由同一个系统进行处理,不需要副本,不增加复杂度,也不增加延迟。

奇特的新加密方法之Part 1:

1.2及更早版本中的X25519

当一个SSL连接建立时,客户端与服务器将对该连接特定的密钥进行磋商,该密钥随后将被用来对应用程序通信进行加密。有几种不同的方法可以做这件事,其中最普遍的一种做法是ECDH(椭圆曲线Diffie-Hellman算法)。长话短说,这种方法依赖于客户端和服务器之间磋商的一个椭圆曲线加密算法。

在Daniel J. Bernstein提出Curve25519算法( X25519是用于ECDH的基于Curve25519算法的机制)以前的很长时间,唯一受到广泛支持的可用曲线算法是由美国国家标准与技术研究院(NIST)定义的。Curve25519算法提出后,很快就被普遍接受,现在它是很多主要浏览器(包括Chrome浏览器)的默认选项。

该算法已被TLS 1.3连接所支持,而现在,对于TLS 1.2及更早版本中的连接,我们依靠BoringSSL就可以在我们这一端支持基于X25519的密钥磋商了。

X25519现在是我们的网络所使用的第二受欢迎的椭圆曲线算法。

奇特的新加密方法之Part 2:

TLS 1.2条件下的RSA-PSS

TLS 1.3所带来的另一个挑战是,用于RSA签名的PSS填充方案(RSASSA-PSS)的采用。该方案在所有TLS 1.3连接条件下代替了RSASSA-PKCS1-v1.5(它较为脆弱,并且从历史上看,更容易受安全漏洞的威胁)。

自从Bleichenbacher的CRYPTO 98这篇文章(该文章展示了SSL/TLS易受加密文本攻击的特点)发表以来,RSA PKCS#v1.5一直被认为容易受到这类攻击。

攻击者利用一个被称为oracle的情境,在该情境中,一个TLS服务器使攻击者可以确定一个给定的加密文本是否按照PKCS1-v1.5规则正确填充。例如,如果服务器对正确的填充和错误的填充返回不同的错误,那么该信息就可以被看成一个oracle(这就是Bleichenbacher在1998年破解SSLv3的方法)。如果错误的填充和正确的填充所造成的握手时间有明显差别,那么这就称为一个计时oracle。

如果一个攻击者已经得到了一个oracle,那么他只需要掌握15000条消息就可以得到足够的信息来执行一个RSA密钥操作,而不需要真正拥有密钥。对于攻击者来说,既可以破解一个以RSA算法加密的文本,也可以伪造一个签名。伪造签名可以使攻击者破解任何不使用前向加密方法的连接。

从那时起,SSL/TLS的实现就采取了应对措施来防范这类攻击,但这类攻击很难正确防范,正如最近发布的F5漏洞所展示的一样。

通过向BoringSSL的转换,我们使RSA PSS在TLS 1.2连接条件下同样可用。其实,“在野外”,它早就被支持了,并且是很多像Chrome一样的现代浏览器在处理RSA服务器证书时的偏好设置。

“月亮的阴暗面”

除了所有这些我们要向客户提供的令人兴奋的新功能以外,BoringSSL也还有少部分终端用户不会注意的内部功能,但这些功能让我们的生活变得更容易了。

我们的一些SSL功能需要一些特殊的补丁,我们在自己的内部OpenSSL分支中对其进行维护,而且,BoringSSL为这些(以及更多的)好功能提供替代品。

一些例子包括,私钥回调支持(我们现在使用这个功能来实现无密钥SSL)、异步会话查找回调(对于不管出于何种原因而不支持会话许可证的与客户端的会话恢复,我们使用这个功能来支持分布式会话ID缓存)、等偏好密码分组(该功能允许我们在提供AES GCM密码的同时提供ChaCha20-Poly1305密码,并让客户端决定使用哪一种)或“选择证书”回调(我们使用这个功能来检查和记录客户端问候信息,并动态地启用那些由用户设置的功能,对于这些功能,我们此前一直使用的是“cert_cb”回调,OpenSSL也支持该回调,但是我们遇到了一些限制,比如不能动态地更改支持的协议版本,或者在会话恢复期间无法执行它)。

缺少OCSP的情形

除了增加新功能之外,BoringSSL开发人员还一直忙于去除那些大多数人不关心的功能,以使代码库更轻便,更易于维护。在很大程度上,这是非常有效的:在没有人注意的情况下,BoringSSL中的大量代码被删除了。

然而,其中一个功能也被砍掉了,那就是OCSP。我们原本非常依赖这一功能来为所有客户自动提供OCSP stapling功能。所以,为了不失去这个功能,我们花了几个星期的时间来制做一个替代品。并且,令人惊喜的是,我们最终得到了比开始时更可靠的OCSP传输渠道。

ChaCha20-Poly1305草案

另一个被删除的功能是对遗留的chacha20-poly1305密码的支持(不要与RFC7905标准的密码混淆)。在标准制定之前,一些浏览器已经部署了这些密码,因此这些密码与较晚被批准的标准密码并不兼容。

我们查看了衡量标准,并意识到很大一部分客户仍然依赖于这个功能。这些客户使用的可能都是较老的移动客户端,没有卸载AES硬件,也没有更新软件来获得较新的ChaCha20密码。

我们决定回到我们自己的内部BoringSSL分支,来重新添加对这些密码的支持,以便那些老客户仍然可以使用它们。我们将继续监控我们的衡量标准,并决定是否在使用量显著下降时移除它们。

缓慢的Base64算法:我来,我见,我征服

我们在测试部署过程中注意到的一个令人烦恼的问题是,我们的NGINX服务器实例的启动时间增加了。依靠perf和flamegraph,我们对情况进行了研究,意识到CPU在BoringSSL的base64解码中愚蠢地花费了大量的时间。

事实证明,在NGINX服务器配置的不同部分,我们一次一次又一次地从磁盘中加载受CA信任的证书(PEM格式,它使用base64算法编码)。并且,由于BoringSSL为了使base64解码的执行时间变得恒定而做出了一个改变,但这也造成执行时间比OpenSSL中慢了好几倍,所以我们的启动时间也受到了负面影响。

当然,聪明的读者可能会问,你为什么一开始就要从磁盘上多次加载这些证书呢?事实上,没有什么特别的原因,只是因为这个问题一开始没有被注意到,直到它真正变成了一个问题。因此,我们修复了配置,只在需要的配置部分才从磁盘中加载证书,从此以后就一直没有这方面的困扰了。

结 语

尽管出现了一些小麻烦,但整个过程还是相当顺利的,这也要归功于BoringSSL代码库的坚如磐石的稳定性,更不用说它的大量文档了。最终我们不仅得到了一个比以前更好、更易于维护的系统,而且我们还为开源社区做了一些微小的工作。

最后,我们要感谢BoringSSL的开发人员,不仅因为他们为项目开发投入了大量的工作,也因为他们一直以来为我们提供的帮助。

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20171218G0DV4A00?refer=cp_1026

相关快讯

扫码关注云+社区