博客 | 首席技术官办公室

超越 C

几十年来,C 语言及其衍生语言一直是系统编程的首选编程语言。 20 世纪 70 年代初,C 语言的开发是汇编语言向前迈出的重要一步。 五十年过去了,我们可以做得更好。

1970 年以及此后的许多年里,计算机安全并没有引起大多数人的关注。 互联网上第一次出现重大安全漏洞是在多年后的 1988 年。 它被称为互联网蠕虫,利用了缓冲区溢出,即内存中的数组的索引超出了其边界。  

在包括 C++ 在内的 C 语言家族中,数组没有进行边界检查。 程序员必须确保数组被正确访问。 因此缓冲区溢出错误很常见。 更糟糕的是,很容易故意造成缓冲区溢出,从而访问不应该访问的内存。

缓冲区溢出只是内存不安全的一个例子。 其他相关示例包括指针运算和悬空指针(又名释放后使用错误)。 如今,我们拥有许多编程语言,它们采用各种技术来保证用这些语言编写的任何程序都不会出现内存安全问题。 C 系列语言不提供这样的保证;内存安全从来都不是这些语言的设计目标。

大约70%的安全漏洞是由于内存安全受到侵犯而造成的。 大量数据支持这一说法。 内存安全考虑以下因素:

  • 67% 的被利用漏洞是在野外披露和检测到的(根据Google Project Zero 2021估计)。
  • 90% 的 Android 漏洞(根据 Google 数据)。 虽然由于使用 Rust,这一数字最近有所下降,但 89% 的远程可利用漏洞仍然与内存安全有关。
  • 70% 的 Microsoft 漏洞(根据 Microsoft 的数据)。
  • 大多数最近的 Apple 漏洞修复(涵盖CatalinaBig SurMontereySafariiOStvOSwatchOS )。

2022年7月, Chrome 103.0.5060.134中修复的漏洞中有5/6是内存安全问题。 显然,消除内存安全漏洞将会非常有帮助。 多年来,业界已经知道如何做到这一点:使用内存安全的编程语言。 从历史上看,问题始终是与性能相关的成本。 由于内存安全的重要性,人们一直在研究新的策略来在不产生传统开销的情况下实现内存安全。 今天我们知道如何以很少甚至零运行时成本消除内存安全错误。 Rust 等语言使用类型系统设计中的创新来保证内存安全,而无需昂贵的运行时支持。

这导致了一个不可避免的结论:停止用 C/C++(或者更普遍地说,用内存不安全的语言)编写新的系统代码。

这并不是要求大规模、不加区别地重写现有代码。 更换现有软件成本高昂,而且存在风险。 然而,行业必须停止在现有代码库中添加更多内存不安全代码来加剧这一问题。 对于现有代码,优先重写最敏感的组件:负责验证或使用不受信任的用户输入的组件、在特权上下文中运行的组件、在沙箱外运行的组件等。

尽管这一观点被广泛接受,但对某些人来说仍然存在争议。 以下是一些支持现状的常见论点以及我们对它们的回应。

  • 错误并不特定于编程语言。  
    • 大多数漏洞是由内存安全漏洞引起的。 在 Rust 等内存安全语言中不可能出现内存安全错误。 因此,使用内存安全的语言将首先防止大多数漏洞的产生。
  • 代码审查将会发现错误。
    • 研究表明,虽然代码审查可能会改善一些事情,但它们往往会忽略许多问题;它们当然无法发现所有问题。
  • 不安全的模块使得整个观点变得毫无意义。
    • 不安全的代码被明确地划分在非常小的代码段中,因此资源可以集中用于验证它。
  • 内存安全语言的实现可能存在缺陷。
    • 确实,但是概率要低得多。 编译器相对较小并且经过严格测试。 修复编译器将自动修复用它编译的所有程序,而不是修复单个程序中的错误。
  • 只有新手或不熟练的程序员才会犯这些错误。
    • 相反,上述数据来自 Chrome 浏览器以及 Windows 和 MacOS 操作系统等主要系统项目。 这些项目配备了业内一些最有能力和最有经验的开发人员,但它们仍然存在内存安全问题。
  • 遵循最佳实践可以避免这些问题。
    • 参见上文。 提到的团队遵循非常严格的实践并使用最好的可用工具。
  • 重写所有代码是不切实际的。
    • 没有人主张彻底重写所有代码。 相反,建议采用专注于关键要素(高权限、大攻击面、安全保障的核心)的方法并使用内存安全语言编写新代码。
  • 效能不足够。
    • Rust 的性能大致与 C/C++ 相当。 细微的差别并不能成为安全风险的理由。 在某些情况下,Rust 程序可以运行得更快。
  • 像 Rust 这样的内存安全系统编程语言太新了。
  • 还有其他解决方案,例如静态分析、模糊测试和沙盒。

参见量化记忆不安全感及其反应 对以上几点进行详细讨论。

尽管有反对意见,但所需变革的势头正在增长。 例如,对开源软件安全基金会(由 Linux 基金会支持)的投资非常大。 美国讨论内存安全 参议院报告和国家安全局的报告。 《消费者报告》还致力于通过向公司和国家机构提供一系列建议来找出可以加速这一运动的各种激励措施。

总结一下:

在过去的五十年里,计算对社会的重要性已经大大增加。 近几十年来,我们计算基础设施所面临的威胁形势也发生了根本性变化。 然而,我们用来构建计算系统的编程语言并没有相应地改变。 缺乏内存安全是软件安全漏洞的最大单一来源。 这并不是任何特定类型的软件所特有的,因为在使用内存不安全的语言的地方,内存安全问题比比皆是。 从数量上看,没有任何其他类别的漏洞能与之媲美。

我们现在有办法解决这个日益严重的问题,而且作为一个行业,我们这样做至关重要。 幸运的是,人们越来越认识到这一情况,但问题十分紧迫,已经没有时间可以浪费了。