几十年来,C 语言及其衍生语言一直是系统编程的首选编程语言。 20 世纪 70 年代初,C 语言的开发是汇编语言向前迈出的重要一步。 五十年过去了,我们可以做得更好。
1970 年以及此后的许多年里,计算机安全并没有引起大多数人的关注。 互联网上第一次出现重大安全漏洞是在多年后的 1988 年。 它被称为互联网蠕虫,利用了缓冲区溢出,即内存中的数组的索引超出了其边界。
在包括 C++ 在内的 C 语言家族中,数组没有进行边界检查。 程序员必须确保数组被正确访问。 因此缓冲区溢出错误很常见。 更糟糕的是,很容易故意造成缓冲区溢出,从而访问不应该访问的内存。
缓冲区溢出只是内存不安全的一个例子。 其他相关示例包括指针运算和悬空指针(又名释放后使用错误)。 如今,我们拥有许多编程语言,它们采用各种技术来保证用这些语言编写的任何程序都不会出现内存安全问题。 C 系列语言不提供这样的保证;内存安全从来都不是这些语言的设计目标。
大约70%的安全漏洞是由于内存安全受到侵犯而造成的。 大量数据支持这一说法。 内存安全考虑以下因素:
2022年7月, Chrome 103.0.5060.134中修复的漏洞中有5/6是内存安全问题。 显然,消除内存安全漏洞将会非常有帮助。 多年来,业界已经知道如何做到这一点:使用内存安全的编程语言。 从历史上看,问题始终是与性能相关的成本。 由于内存安全的重要性,人们一直在研究新的策略来在不产生传统开销的情况下实现内存安全。 今天我们知道如何以很少甚至零运行时成本消除内存安全错误。 Rust 等语言使用类型系统设计中的创新来保证内存安全,而无需昂贵的运行时支持。
这导致了一个不可避免的结论:停止用 C/C++(或者更普遍地说,用内存不安全的语言)编写新的系统代码。
这并不是要求大规模、不加区别地重写现有代码。 更换现有软件成本高昂,而且存在风险。 然而,行业必须停止在现有代码库中添加更多内存不安全代码来加剧这一问题。 对于现有代码,优先重写最敏感的组件:负责验证或使用不受信任的用户输入的组件、在特权上下文中运行的组件、在沙箱外运行的组件等。
尽管这一观点被广泛接受,但对某些人来说仍然存在争议。 以下是一些支持现状的常见论点以及我们对它们的回应。
参见量化记忆不安全感及其反应 对以上几点进行详细讨论。
尽管有反对意见,但所需变革的势头正在增长。 例如,对开源软件安全基金会(由 Linux 基金会支持)的投资非常大。 美国讨论内存安全 参议院报告和国家安全局的报告。 《消费者报告》还致力于通过向公司和国家机构提供一系列建议来找出可以加速这一运动的各种激励措施。
总结一下:
在过去的五十年里,计算对社会的重要性已经大大增加。 近几十年来,我们计算基础设施所面临的威胁形势也发生了根本性变化。 然而,我们用来构建计算系统的编程语言并没有相应地改变。 缺乏内存安全是软件安全漏洞的最大单一来源。 这并不是任何特定类型的软件所特有的,因为在使用内存不安全的语言的地方,内存安全问题比比皆是。 从数量上看,没有任何其他类别的漏洞能与之媲美。
我们现在有办法解决这个日益严重的问题,而且作为一个行业,我们这样做至关重要。 幸运的是,人们越来越认识到这一情况,但问题十分紧迫,已经没有时间可以浪费了。