crypto/tls 库中的自动化加密套件(Cipher Suite )排序

未匹配的标注

本文为官方 Go Blog 的中文翻译,详见 翻译说明

菲利波-瓦尔索尔达
2021年9月15日

Go 标准库提供了crypto/tls,这是传输层安全(TLS)的强大实现,是互联网上最重要的安全协议,也是 HTTPS 的基本组成部分。在 Go 1.17 中,我们通过自动调整密码套件的优先级顺序,使其配置更简单、更安全、更高效。

密码套件如何工作

密码套件可以追溯到TLS的前身安全套接字层(SSL),称它们为"密码种类"。它们是看起来很吓人的标识符,如TLS_RSA_WITH_AES_256_CBC_SHATLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,阐明了用于在TLS连接中交换密钥、认证证书和加密记录的算法。

密码套件在TLS握手过程中是协商的:客户端在其第一个消息中发送它所支持的密码套件的列表,即客户端你好,服务器从该列表中选择一个,并将其选择传达给客户端。客户端以自己的偏好顺序发送所支持的密码套件列表,而服务器可以自由地从中挑选它。最常见的是,服务器会根据其配置,按照客户端的偏好顺序或服务器的偏好顺序,挑选第一个相互支持的密码套件。

密码套件实际上只是许多协商参数中的一个—支持的曲线/组和签名算法是通过他们自己的扩展来协商的--但却是最复杂和最著名的参数,也是多年来开发人员和管理员被训练得有意见的唯一参数。

在TLS 1.0-1.2中,所有这些参数在一个复杂的相互依赖的网络中相互作用:例如,支持的证书依赖于支持的签名算法、支持的曲线和支持的密码套件。在TLS 1.3中,这一切都被大大简化了:密码套件只指定对称加密算法,而支持的曲线/组管理密钥交换,支持的签名算法适用于证书。

一个复杂的选择被放弃给了开发者

大多数HTTPS和TLS服务器将密码套件的选择和偏好顺序委托给服务器运营商或应用程序开发人员。这是一个复杂的选择,需要最新的和专门的知识,原因很多。

一些旧的密码套件有不安全的组件,一些需要极其仔细和复杂的实现才是安全的,一些只有在客户端应用某些缓解措施或甚至拥有某些硬件时才是安全的。除了单个组件的安全性,不同的密码套件可以为整个连接提供截然不同的安全属性,因为没有 ECDHE 或 DHE 的密码套件不提供前向保密性--连接不能被追溯或被动地用证书的密钥解密的属性。最后,所支持的密码套件的选择会影响到兼容性和性能,在没有对生态系统进行最新了解的情况下进行改变,可能会导致传统客户端的连接中断,增加服务器消耗的资源,或耗尽移动客户端的电池。

这种选择是如此神秘和微妙,以至于有专门的工具来指导操作者,如优秀的Mozilla SSL配置生成器.。

我们是如何走到这一步的,为什么会变成这样?

首先,单个加密组件曾经更频繁地被破坏。2011年,当 BEAST 攻击破坏了 CBC 密码套件,以至于只有客户端可以缓解攻击时,服务器转而倾向于使用不受影响的RC4。2013年,当RC4明显被破坏时,服务器又回到了 CBC。当 Lucky Thirteen 明确表示,由于其向后的 MAC-then-encrypt 设计,实施 CBC 密码套件是非常困难的......好吧,没有任何其他东西在桌子上,所以实施者不得不小心翼翼地跳过障碍来实施CBC,并一直在这个艰巨的任务中失败了多年。可配置的密码套件和加密灵活性曾经提供了一些保证,当一个组件损坏时,它可以被即时替换。

现代密码学则明显不同。协议仍然会时不时地发生故障,但很少是单个抽象的组件发生故障。 从2008年 TLS 1.2 开始引入的基于 AEAD 的密码套件没有一个被破坏。 这些天,密码学的敏捷性是一种责任:它引入了可能导致弱点或降级的复杂性,而且它只是出于性能和合规性的原因而需要。

补丁曾经也是不同的。今天,我们承认及时为已披露的漏洞打上软件补丁是安全软件部署的基石,但在十年前这还不是标准做法。改变配置被认为是应对有漏洞的密码套件的一个更快速的选择,所以操作者通过配置,完全负责它们。我们现在有一个相反的问题:有一些完全打了补丁和更新的服务器仍然表现得很奇怪,不理想,或者不安全,因为他们的配置已经多年没有被触及。

最后,人们了解到,服务器往往比客户更新得更慢,因此对密码套件的最佳选择的判断不太可靠。然而,因为服务器对密码套件的选择有最后的决定权,所以默认成为让服务器服从于客户的偏好顺序,而不是有强烈的意见。这仍然是部分正确的:浏览器设法使自动更新发生,并且比一般的服务器要更新的多。另一方面,一些传统的设备现在已经不支持了,而且还停留在旧的 TLS 客户端配置上,这往往使得一个最新的服务器比一些客户端更有条件选择。

不管我们是如何走到这一步的,要求应用程序开发人员和服务器操作员成为密码套件选择的细微差别的专家,并保持最新的发展,以保持他们的配置是最新的,这是密码学工程的失败。如果他们部署了我们的安全补丁,这就足够了。

Mozilla 的 SSL 配置生成器很好,它不应该存在。

这是否会变得更好?

在过去的几年里,事情的发展趋势有好消息和坏消息。坏消息是,排序变得更加细微,因为有几组密码套件具有同等的安全属性。在这样一个集合中的最佳选择取决于可用的硬件,并且很难在一个配置文件中表达。在其他系统中,开始是一个简单的密码套件列表,现在取决于更复杂的语法或附加标志,如SSL_OP_PRIORITIZE_CHACHA

好消息是,TLS 1.3极大地简化了密码套件,它使用的是与 TLS 1.0-1.2 不相干的一套密码。所有的TLS 1.3密码套件都是安全的,所以应用程序开发人员和服务器操作员根本不需要担心它们。事实上,一些TLS 库如 BoringSSL 和 Go 的crypto/tls根本不允许配置它们。

Go's crypto/tls and cipher suites

Go 确实允许在 TLS 1.0-1.2 中配置密码套件。应用程序一直能够通过Config.CipherSuites来设置启用的密码套件和偏好顺序。服务器默认会优先考虑客户端的偏好顺序,除非Config.PreferServerCipherSuites被设置。

当我们在 Go 1.12 中实现 TLS 1.3 时,我们没有让TLS 1.3密码套件可配置,因为它们是一个与 TLS 1.0-1.2 不相干的集合,最重要的是它们都是安全的,所以没有必要将选择权交给应用程序。 Config.PreferServerCipherSuites仍然控制着哪一方的偏好顺序,而本地方的偏好取决于可用的硬件。

在 Go 1.14 中,我们暴露了支持的密码套件,但明确选择了以中立的顺序(按 ID 排序)来返回,这样我们就不会最终被束缚在以静态排序的方式来表示我们的优先级逻辑。

在 Go 1.16 中,当我们检测到客户端或服务器缺乏对 AES-GCM 的硬件支持时,我们开始主动在服务器上优先选择 ChaCha20Poly1305 密码套件。这是因为如果没有专门的硬件支持(如 AES-NI 和 CLMUL 指令集),AES-GCM 很难有效和安全地实现。

最近发布的Go 1.17,接管了所有Go用户的密码套件偏好排序。虽然Config.CipherSuites仍然控制哪些 TLS 1.0-1.2 密码套件被启用,但它不用于排序,Config.PreferServerCipherSuites现在被忽略。相反,crypto/tls根据可用的密码套件、本地硬件和推断的远程硬件能力,做出所有排序决定

当前TLS 1.0-1.2的排序逻辑遵循以下规则。

  1. ECDHE 优于静态的RSA密钥交换。

    一个密码套件最重要的属性是实现前向保密性。我们不实现 "经典的 "有限域Diffie-Hellman,因为它很复杂,速度较慢,较弱,而且在TLS 1.0-1.2中巧妙地被破坏,所以这意味着优先考虑椭圆曲线Diffie-Hellman密钥交换而不是传统的静态RSA密钥交换。(后者只是使用证书的公钥对连接的秘密进行加密,如果证书在未来被破坏,就有可能被解密)。

  2. AEAD 模式比 CBC 模式更适合用于加密。

    即使我们为 Lucky13(我对Go标准库的第一个贡献,早在2015年!)实现了部分对抗措施,CBC 套件也是要做好的噩梦,所以在其他更重要的事情上,我们选择 AES-GCM 和 ChaCha20Poly1305 代替。

  3. 3DES、CBC-SHA256 和 RC4 只有在没有其他可用的情况下才会使用,其优先顺序为:3DES。

    3DES 有64位块,这使得它在足够的流量下,从根本上容易受到生日攻击。3DES 被列在InsecureCipherSuites下,但为了兼容,它被默认启用。(控制优先顺序的另一个好处是,我们可以让较不安全的密码套件在默认情况下启用,而不必担心应用程序或客户选择它们,除非是最后的手段。这是安全的,因为没有降级攻击,即依靠较弱的密码套件的可用性来攻击支持更好的替代方案的对等者)。

    CBC密码套件容易受到 Lucky13 式的侧信道攻击,我们只对 SHA-1 哈希值部分实现了上面讨论的复杂对策,而不是对SHA-256。CBC-SHA1 套件有兼容性价值,证明了额外的复杂性,而 CBC-SHA256 套件没有,所以它们默认是禁用的。

    RC4 有实际可利用的偏差,可以导致明文恢复而不需要侧信道。没有比这更糟糕的了,所以RC4被默认禁用。

  4. ChaCha20Poly1305 比 AES-GCM 更适合用于加密,除非双方都有对后者的硬件支持。

    正如我们上面所讨论的,AES-GCM 在没有硬件支持的情况下很难有效和安全地实现。如果我们检测到本地没有硬件支持,或者(在服务器上)客户端没有优先考虑 AES-GCM,我们会选择ChaCha20Poly1305 来代替。

  5. AES-128 比 AES-256 更适合用于加密。

    AES-256 比 AES-128 有更大的密钥,这通常是好的,但它也执行了更多轮的核心加密功能,使其更慢。(AES-256 中的额外轮次与密钥大小的变化无关;它们是为了提供更广泛的余量来防止密码分析。) 更大的密钥只在多用户和后量子设置中有用,这与 TLS 无关,TLS 生成足够随机的 IV,并且没有后量子密钥交换支持。由于较大的密钥没有任何好处,我们更喜欢 AES-128 的速度。

TLS 1.3 的排序逻辑 只需要最后两条规则,因为 TLS 1.3 取消了前三条规则所防范的问题算法。

FAQs

如果一个密码套件被发现有问题怎么办? 就像其他的漏洞一样,它将在所有支持的 Go 版本的安全版本中被修复。所有的应用程序都需要准备好应用安全修复,以便安全地运行。从历史上看,破译的密码套件越来越少。

为什么让启用的 TLS 1.0-1.2 密码套件可配置?在选择启用哪些密码套件时,需要在基本的安全和传统的兼容性之间做出有意义的权衡,这是一个我们自己无法做出的选择,否则会砍掉生态系统中不可接受的一块,或者减少现代用户的安全保障。

为什么不使 TLS 1.3 的密码套件可配置呢? 相反,TLS 1.3 不需要进行权衡,因为它的所有密码套件都提供了强大的安全性。这让我们可以将它们全部启用,并根据连接的具体情况选择最快的,而不需要开发者的参与。

主要收获

从 Go 1.17 开始,crypto/tls正在接管选择可用密码套件的顺序。在定期更新的 Go 版本中,这比让可能过时的客户端选择顺序更安全,让我们优化性能,并且从 Go 开发者那里消除了大量的复杂性。

这与我们的总体理念是一致的,即只要有可能,我们就会做出加密决定,而不是将其委托给开发者,也符合我们的加密原则。希望其他TLS库也能采用类似的变化,使精细的密码套件配置成为过去。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/go-blog/automat...

译文地址:https://learnku.com/docs/go-blog/automat...

上一篇 下一篇
Summer
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~