内存安全“卷曲”,实现更安全的互联网

2020-10-11 15:33:30

TLDR:已经开始让Hyper在用于HTTP的cURL中作为后端工作。

CURL和它的数据传输核心libcurl都是用C语言编写的。C语言以内存不安全而臭名昭著,很容易搞砸,从而意外地导致安全问题。

同时,C编译器得到了非常广泛的使用和使用,您可以为几乎所有的操作系统和CPU编译C程序。C程序可以比用几乎任何其他编程语言编写的代码更具可移植性。

Curl是一段“不安全”的C代码,安装在全世界大约100亿台安装中。我用引号说不安全,因为我不认为卷曲是不安全的。当然,我们也有自己的安全漏洞,即使我认为在过去几年中发现这些漏洞的比率已经大幅降低,但我们从来没有遇到过严重的漏洞,在大量工具和人员的帮助下,我们在代码落入用户手中之前发现并修复了大多数问题。(“内存安全”并不是导致安全问题的唯一原因。)。

我相信在未来很长一段时间内,curl和libcurl将继续广泛使用:curl是任何地方的脚本和设置中的既定组件和伙伴。在进行互联网传输的地方,libcurl几乎是一个事实上的标准。

不考虑将cURL重写为另一种语言。移植像libcurl这样的旧的、已建立的和使用得很好的代码库是一项巨大而艰巨的任务,它在很大程度上由于稳定的API而广受欢迎和传播,不会破坏ABI,也不会改变现有功能的行为。到目前为止,它还没有被认真尝试过,甚至连考虑过它的大公司都放弃了这样的想法。

上面的这段序言可能会让人觉得,只要使用curl和libcurl,我们就会被困在我们所拥有的东西上。但不要害怕:事情比乍看起来更复杂,或者可能更光明。

对于libcurl的用户来说,重要的是要保持完好无损。我们保留API、ABI、行为以及所有记录在案的选项和功能。我们还需要不断增加内容,跟上世界前进的步伐。

今天,您已经可以构建libcurl来使用TLS、SSH、名称解析、LDAP、IDN、GSSAPI和HTTP/3的不同“后端”。

在此上下文中的“后端”是cURL中的一段代码,它允许您使用特定的解决方案(通常涉及特定的第三方库)来实现特定的libcurl功能。例如,使用此设置,您可以选择使用13个不同的TLS库中的一个或多个构建libcurl。您只需在构建它时选择您喜欢的一个(或多个)即可。Libcurl API对用户来说保持不变,只是有些特性和功能可能会稍有不同。当然,TLS后端的数量也会随着时间的推移而变化,因为我们将来会增加对更多库的支持,甚至会在旧库逐渐消失时放弃对它们的支持。

在构建cURL时,您现在可以让它使用多达33个不同的第三方库来实现不同的功能。它们中的许多当然是相互排斥的,所以没有一个单一的构建可以使用所有33个。

换句话说:您可以在不更改任何代码的情况下改进curl和libcurl二进制文件,只需将其重新构建为使用另一个后端组合即可。

有了大量使用第三方库的后端,libcurl的工作在很大程度上就变成了提供的稳定外部API和执行繁重任务的特定第三方库之间的切换。

自由卷曲像岩石一样,有一扇门,进门的规则都是用石头写的。后端可以来来去去,可以更改和改进,但入口外的应用程序不会注意到这一点。他们得到了他们了解和信任的稳定的API和ABI。

此设置提供了一个基础和基础设施,可以将用其他语言编写的后端作为包的一部分提供。只要这些库有libcurl可以访问的API,后端使用的库就可以用任何语言编写-但由于我们在这篇博客文章中讨论的是内存安全,最明显的选择可能是一种现代且安全的语言。例如,铁锈。

使用用Rust编写的后端库,libcurl将依靠这样的组件来执行低级协议工作,这样做可能会增加实现安全可靠的机会。

上面的世界地图图像中已经支持的第三方库中有两个是用Rust编写的:quiche和Mesalink。

Hyper是用Rust编写的HTTP库。它应该是快速、准确和安全的,它同时支持HTTP/1和HTTP/2。

随着libcurl后端数量不断增加,我们又迈出了一步,开始确保curl(可选)可以构建为使用Hyper。

这项工作得到了ISRG的慷慨资助,ISRG可能最为人所知的就是“让我们加密”背后的组织。谢谢!。

我想强调的是,现在还为时尚早。我们知道我们想要做什么,我们基本上知道如何做,但从那里到真正完成它,并将其以源代码的形式提供给世界,这是一项尚未完成的工作。我已经准备好去做这件事了。

Hyper没有C API,他们正在努力开发一个,这样基于C的应用程序(如cURL)就可以实际使用它。我尽了最大努力从我的角度提供反馈,但由于我对Rust不是很感兴趣,所以我不能在那里的实现部分提供太多帮助。

一旦有了API的早期/alpha版本可供试用,我将首先确保curl可以构建为使用Hyper,然后开始查看代码以开始使用它。

在这项工作中,我希望我必须带着问题、反馈和文档建议回到API。我还预见到将libcurl内部转换为使用它的挑战。大部分是小的,但也可能是大的。

我已经创建了一个git分支,并在早期将我在这个网站上的工作公之于众,让每个想要的人都能跟上发展的步伐。第一个里程碑将是成功运行单个CURL测试用例(任何测试用例)的能力--不加修改。分支在这里:https://github.com/curl/curl/tree/bagder/hyper-注意它将频繁地改变基数。

这个项目没有最后期限,我还没有任何猜测,因为什么时候会有什么东西来测试。

这个项目对于未来的开发人员来说是真正的基础工作,因为这里处理的一些问题应该也会使其他人受益。例如,很明显,Rust通常鼓励在内存不足问题上中止,而当代码在系统库(如cURL)中使用时,这是一个很大的禁忌。

我在这里的细节有点含糊,因为这不是我的专业知识,但是Rust本身甚至不能正确地清理它的内存,当它遇到这样的条件时,它只是返回错误。显然,在使用hyper进行libcurl之前需要修复的东西可能会声明相同的行为,并且永远不会泄漏内存。

我们将致力于这个项目,让这种未来成为可能,我们的心态是它可以让用户受益。

如果真的发生,则涉及许多不同的因素(例如成熟度、功能集、内存占用、性能、可移植性和磁盘占用…)。特别是,它将在很大程度上依赖于构建和发布您使用的curl包的人员-这不是cURL项目本身,因为我们只发布源代码。我在考虑Linux和操作系统发行版等。

什么时候可能会发生,我们还不能确定,因为我们在这个过程中还为时过早。

不要上当受骗,以为我们采取这一步就可以摆脱卷曲的C。随着Hyper Powered后端的引入,我们肯定会将在典型HTTP传输中执行的C代码份额减少一个可测量的量(对于那些构建),但cURL远不止于此。

在您所关心的平台上,Hyper后端甚至不一定会“赢得”与C实现的用户竞争。未来还没有确定。

当然,有何不可?正在努力提供更多用Rust编写的后端。渐渐地,我们可能会进入这样一个未来:最终的curl和libcurl可执行代码越来越少地从C编译而来。

当然,这将如何以及是否会发生,将取决于许多因素-特别是必要工作的资金。

我们是否可以进一步推动这方面的发展呢?我认为现在推测这一点还为时过早。让我们先来看看未来几十年的前几集结果如何。