前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >成为必选项:Rust极简史2024版

成为必选项:Rust极简史2024版

原创
作者头像
程序员吾真本
修改2024-10-17 00:06:04
360
修改2024-10-17 00:06:04
举报
文章被收录于专栏:Rust避坑式入门

2003年1月25日清晨,全球互联网基础设施遭遇了一次严重的安全事件。SQL Slammer蠕虫病毒迅速传播,导致大规模网络中断。

蠕虫病毒是一种自我复制的恶意程序,能够通过网络自主传播。它通过利用目标计算机的安全漏洞,将其转化为传播媒介,继而扫描并感染其他设备。这种递归式的自我复制机制使得蠕虫病毒能够快速扩散,主要通过消耗网络带宽来影响系统运行。

SQL Slammer蠕虫利用了微软SQL Server和数据引擎软件中的一个特定漏洞。其传播速度之快令人震惊,通过产生大量网络流量来使系统瘫痪,实现了分布式拒绝服务(DDoS)攻击。在短短几分钟内,它就严重干扰了互联网的核心功能,甚至导致13个根DNS服务器中的5个无法正常运作。据估计,仅在爆发的前五天,这种蠕虫就造成了高达9.5亿至12亿美元的经济损失。

SQL Slammer蠕虫的核心攻击手段是利用缓冲区溢出(Buffer Overflow)这一内存安全漏洞。具体来说,它针对微软SQL Server和Desktop Engine数据库产品中的一个已知漏洞(CVE-2002-0649)进行攻击。缓冲区溢出是一种常见的内存安全问题,当程序尝试将超出预定大小的数据写入内存缓冲区时,就可能导致程序异常行为或允许攻击者执行未经授权的代码。

想象一下,在古代军队中,每位将军都有一本专门用于记录皇帝命令的本子,每页记录一条命令。这本子中的每一页,就像计算机中的缓冲区,有固定的大小(即内存容量)。

缓冲区溢出就好比有人试图在已经写满的本子页面上继续添加内容。正常情况下,当页面写满时,我们应该停止书写。但如果没有适当的保护措施,允许继续写下去,多余的内容就会"溢出"到下一页,可能覆盖其他重要文件或命令。

在计算机世界中,这种"溢出"可能导致程序崩溃,就像军队因执行错误的命令而陷入混乱。更糟糕的是,如果有心怀不轨之人故意制造这种溢出,他们可能会借机插入自己的"命令"(恶意代码),如同敌军间谍篡改将军的命令本,从而控制整个系统。

这就是缓冲区溢出如此危险的原因:它不仅可能导致系统故障,还可能被黑客利用来执行未经授权的操作,威胁整个系统的安全。就像一个被篡改的命令可能使整支军队陷入危险,一个被利用的缓冲区溢出漏洞可能危及整个计算机网络。

在SQL Slammer蠕虫的攻击过程中,恶意代码向目标服务器发送超出其容纳能力的数据量,如同超出将军命令本一页的容量而溢出到下一页。这导致服务器内存被篡改,使攻击者能够在受感染的服务器上执行恶意指令。蠕虫会自动生成随机IP地址,并向那些未及时更新安全补丁的SQL Server发送自身代码。被感染的服务器随后会重复这一过程,从而在全球范围内迅速扩散感染,最终导致全球范围内的网络服务中断。

1

说起SQL Slammer蠕虫,不由得让人回想起再往前15年的莫里斯蠕虫事件。1988年11月2日,康奈尔大学研究生罗伯特·塔潘·莫里斯在互联网上释放了这一病毒,随后迅速蔓延。莫里斯蠕虫利用了Unix系统的漏洞,特别是Finger服务中的缓冲区溢出问题。通过向Finger服务发送超长的输入数据包,蠕虫触发了缓冲区溢出,进而覆盖关键程序内存,使攻击者得以执行未经授权的代码。尽管并非蓄意破坏,但蠕虫的快速复制严重影响了受感染机器的性能,导致当时约10%的互联网系统瘫痪。此事件还成为美国《计算机欺诈和滥用法》下的首例定罪案件。

缓冲区溢出等内存安全漏洞为何频繁发生?根本原因是在用于开发系统级软件的C/C++编程语言中,内存安全机制并非必选项,而仅是可选项。

如何理解内存安全是必选项还是可选项?想象一下,C/C++编程语言就像一个大型工厂,而内存安全机制则是工厂的安全系统。

必选项的内存安全机制犹如一个严格、自动化的安全系统。它在生产线上设置多个检查点,一旦发现任何安全隐患(如内存安全问题),立即停止生产线并发出警报。工人们必须解决这些问题,否则无法重启生产线。这就像Rust编译器在发现内存安全问题时会报错,并阻止生成可运行代码,不修复不罢休。

相比之下,C/C++中长久以来一直存在的可选项内存安全机制更像一个松散、手动的安全系统。在这个系统中:

  • 工厂管理层(即编译器)对安全问题通常采取不干预态度,即使存在潜在的安全隐患,也允许生产线(代码编译)继续运行。
  • 工厂提供了一些安全检查工具(如静态分析工具),但使用与否完全取决于工人(程序员)的自觉。
  • 工厂墙上贴有安全操作指南(编程良好规范),图书馆的书中也散落一些指南,但工人是否能发现、找到并遵循这些指南,同样完全自愿。

在这种情况下,安全隐患很容易被忽视或遗漏,导致事故(内存安全问题)频繁发生。这就解释了为什么在C/C++中,内存安全漏洞如此普遍:因为安全机制是可选的,而非强制执行的。

系统级软件是直接与硬件交互的底层软件,需要高性能和高效率。这类软件包括操作系统(如莫里斯蠕虫攻击的Unix系统)、设备驱动程序、嵌入式系统、实时系统、数据库引擎(如SQL Slammer蠕虫攻击的微软SQL Server和Desktop Engine数据库产品)、编译器和网络协议栈等。这些软件通常需要精确的资源控制、底层硬件访问和高效的性能优化。

从1972年C语言首次发布,到1985年C++作为C语言的扩展问世,再到SQL Slammer蠕虫发作的2003年,这30年间C/C++在系统级软件开发领域占据统治地位。这主要归功于C/C++在性能和资源控制、精细内存管理、跨平台兼容性、标准化、成熟工具链、丰富系统库和接口,以及广泛的社区支持和行业经验等方面的优势。

值得注意的是,微软SQL Server和Desktop Engine数据库产品均采用C语言和C++开发,而Unix系统则主要使用C语言和汇编语言编写。

如前所述,尽管C/C++在系统级软件开发市场占据统治地位,但这两种语言本身并未内置内存安全保障机制,程序员需要手动管理内存。这容易引发各种内存错误,如缓冲区溢出、悬垂指针和内存泄漏等。

当然,C/C++开发者可以通过两种方法来提高内存安全性:遵循最佳编程实践,和使用辅助工具(如智能指针和内存泄漏检测工具、静态分析工具),但这些措施都是可选的,且无法在编译时完全强制执行。开发者可能会忽视这些规范或工具的使用。

C/C++将内存安全作为可选项的做法,自语言诞生以来,一直是系统级软件因内存安全问题而崩溃的主要原因。C/C++开发者和系统级软件用户长期面临这一挑战。天下苦C/C++久矣!这种困境持续存在,直到2006年一起电梯故障事件成为转折点,并最终成为撼动C/C++在系统级软件开发市场统治地位的催化剂。

2

2006年的一天,住在温哥华的加拿大C/C++程序员格雷登·霍尔(Graydon 霍尔)准备回家。当他来到电梯口时,震惊地发现门上贴着一则通知:电梯因软件崩溃而无法使用。他家在21层。一边爬楼,霍尔一边思考:电梯的控制软件属于嵌入式系统,很可能是用C/C++编写的,而软件崩溃极有可能是因为内存安全问题。"我们这些倒霉的C/C++程序员,在公司修复系统崩溃的bug也就算了,为什么回到家还要遭受软件崩溃之苦?"他暗自抱怨道。

C/C++程序员们!系统级软件用户们!难道就没有一种能给咱们带来安全感的编程语言吗?!

2019年10月10日,霍尔在usesthis.com网站上自我介绍时表示,他是一位社会主义者,关注公共服务、基础设施投资和工人权益。这不禁让人联想到他的前辈——那位不远万里来到中国,为病患村民和受伤士兵提供医疗援助的白求恩大夫。

还没爬到21层,霍尔就已经下定决心:他要利用业余时间,为千千万万饱受折磨的C/C++程序员和系统级软件用户,开发一门将内存安全作为必选项的编程语言。

给这门语言起什么名字好呢?霍尔想到了锈菌(rust fungi)。

锈菌是一种植物病原体,会在植物表面形成铁锈色的孢子沉积。作为寄生物,它们需要活体宿主来完成复杂的生命周期,这通常涉及两种不同的植物宿主。这些真菌能感染植物的各个部位,减缓其生长和产量,但不会直接杀死宿主。由于锈菌会影响众多经济作物(如小麦、咖啡和大豆),它成为了农业领域的一大关注重点。

锈菌通常需要两种不同的植物物种来完成其生命周期。这个生命周期涉及产生不同类型的孢子,每种孢子都专门用于感染两种宿主中的一种。通过感染两个不同的宿主,锈菌可以更有效地在生态系统和季节之间传播,通过多样化其栖息地来确保生存,并减少在一种宿主物种不可用或变得具有抗性时被消灭的机会。这种复杂的策略增强了它们在各种环境中持续生存的能力。

霍尔设计的新编程语言要把内存安全作为必选项。与C/C++的设计理念相比,这可以说是一种"过度设计"。

然而,为了确保软件不崩溃而稳定地生存,这种"过度设计"恰恰是必需的。

锈菌拥有高度复杂的生命周期,通常涉及多个宿主和不同的产孢阶段。这种复杂性确保了它们在各种环境中的生存能力。霍尔意识到,这正象征着新语言的"为生存而过度设计"理念。

Rust编译器在发现内存安全问题后报错,不修复不罢休,就是这种必需的过度设计。

好,就它了。新语言就叫Rust。

在接下来的3年里,霍尔利用业余时间将Rust作为个人项目进行开发。他精心设计了Rust的以下特性:

  • 内存安全,杜绝野指针。
  • 强大的类型系统,消除空指针。
  • 变量默认不可变,严格控制可变性。
  • 允许打破内存安全规则,但开发者需自担风险。
  • 标准模式下,这些规则由语言本身实现,而非依赖外部工具,便于检查。
  • 支持多种编程范式。
  • 摒弃"一切皆对象"的理念。
  • 针对不同问题提供不同抽象,在控制、表达、清晰与简洁之间寻求平衡。

经过3年努力,Rust语言约90%的特性基本可用,70%左右的运行时特性已经实现。为构建Rust编译器,霍尔用OCaml语言编写了38000行代码。

2009年,霍尔思考道:"我设计的这个解决C/C++内存安全问题的Rust语言已经基本成型,但仅凭一己之力,力量还是太小。我所在的Mozilla这家开源软件公司,也在用C/C++开发Firefox浏览器。何不利用Rust的内存安全优势,尝试说服公司领导呢?这样或许能获得公司支持,加快Rust的开发进程。"

他随即向公司领导展示了Rust。果不其然,那些被C/C++内存安全问题折磨得焦头烂额的领导们对Rust大为赞赏。公司决定投资Rust项目,而霍尔自然成为了Rust语言开发核心团队的第一位成员,以及Rust语言开发的"仁慈老大"(BDFL, Benevolent Dictator For Life)。

"仁慈老大"是授予少数开源软件开发领袖的头衔,通常指在社区内争议或争论中保留最终决定权的项目创始人。这一称呼起源于1995年。Python的创始人吉多·范罗苏姆(Guido van Rossum)就曾是Python语言的仁慈老大。

为什么要仁慈呢?因为在主要由无偿志愿者参与的开源软件社区中,如果领导者不够仁慈,那么在激烈争论后,持反对意见的志愿者很可能会从代码主干分出新分支,另起炉灶,导致项目分裂。

Mozilla公司对Rust的投入可谓不遗余力。在接下来的10年里,公司调配了10多位程序员全职开发Rust语言。这种慷慨的投入并非无的放矢。要知道,Mozilla开发的Firefox浏览器约有450万行C/C++代码。更值得注意的是,Mozilla在2019年2月28日发布的一份安全漏洞分析报告中揭示,在34个严重或高风险漏洞中,高达32个与内存相关。霍尔将内存安全作为必选项的Rust语言设计,无疑正中公司领导的痛处。

3

2010年,Rust语言开发的重点任务是将原本用OCaml编写的Rust编译器迁移至基于LLVM的自托管编译器。这个新编译器将用Rust语言本身编写,以实现"自举"。

在Mozilla公司的大力支持和霍尔的领导下,Rust语言不断完善,开发团队也逐步壮大。

霍尔为人低调,网上仅能找到这一张他的照片
霍尔为人低调,网上仅能找到这一张他的照片

2011年,Rust核心团队终于完成了自举。从此,Rust编译器可以用自身编译Rust代码,标志着Rust语言迈过了自给自足的重要里程碑。

2011年秋,一位热爱自行车运动的Rust团队成员设计出了Rust语言的logo。灵感来自其所钟爱的自行车齿轮。齿轮作为自行车中的重要机械部件,象征着强大、可靠和高效的工程设计,这与Rust语言强调的内存安全、性能以及并发处理的特点不谋而合。齿轮的形象恰如其分地传递出Rust作为系统编程语言的坚固和精密特性。

2011年,担任"仁慈老大"的霍尔发现,每次与核心团队成员讨论Rust语言设计时,他几乎总是处于劣势。在2023年6月4日发表的博客《我想要的Rust没有未来》中,他列举了10次关键讨论中的失利。让我们来品味其中几个。

关于跨crate内联与单态化(cross-crate inlining and monomorphization),霍尔倾向于crate内部允许内联,但对外保持稳定入口点的方案,类似于后来Swift的设计。这本可以缓解Rust的长编译时间和缺乏稳定ABI(Application Binary Interface,应用程序二进制接口)的问题。然而,团队最终选择了允许跨crate内联,虽然在某种程度上提高了性能,但也带来了编译时间延长和ABI不稳定的问题。ABI定义了程序在二进制层面的通信规则,确保不同软件模块(如函数、库、操作系统)能够正确地相互调用、传递数据和交换信息。

对于库定义的容器、迭代和智能指针,霍尔主张将这些作为编译器的内建功能,直接在使用点展开代码,而非通过库实现。这样可以避免用户代码引入的性能损失。但团队最终选择了通过库提供这些功能,尽管增加了一些性能开销,却提高了语言的灵活性和可扩展性。

关于异步/等待(Async/await)特性,霍尔倾向于采用标准的绿色线程运行时(具有可增长栈),以支持简单的协程机制,这与Go语言的协程实现类似。尽管Rust最初有相似的机制,团队最终选择了基于async/await的模型,旨在提升性能和灵活性。霍尔勉强接受了这一决定。他在博客中表示,若他是一位更强势的"仁慈老大",他会坚持自己的方案。可见,霍尔还是心太软了。

对于&符号的地位,霍尔主张将其作为"二等公民",仅用于参数传递模式,不允许从函数返回或放入结构体中。他认为这种限制能降低认知负担。然而,团队决定将&符号提升为"一等公民",虽然增加了复杂性,但大大增强了Rust的表达能力。

在生存期(Lifetimes)问题上,霍尔希望生存期推断能够完全自动化,无需显式声明生存期变量。他认为显式生存期的复杂度超过了其带来的收益。尽管如此,团队仍将显式生存期作为Rust的核心特性之一,即便它未能实现完全自动推断。

关于环境捕获(Environment capture),霍尔不赞同闭包中的环境捕获,认为这在系统编程语言中引入了不必要的复杂性和潜在副作用。然而,团队最终决定让Rust允许闭包捕获环境,以提高代码的灵活性和简洁性。霍尔推测这是为了便于在LLVM中实现外部迭代器,但他在博客中仍然表达了对这一设计的反对意见。

对于trait,霍尔不喜欢这种类似typeclass的trait设计,认为它过于类型导向,且导致库之间的耦合。他更倾向于采用ML传统中的模块系统。尽管如此,团队最终选择了trait系统,因为它提供了更强的表达能力和灵活性,即便这使得代码变得更加复杂。

在复杂推断(Complex inference)方面,霍尔希望保持Rust的类型推断简单,仅对局部变量进行推断,避免过于复杂的类型系统。但团队却选择了让Rust的类型推断变得非常复杂,以支持更强的表达能力,特别是在涉及泛型和trait时。

霍尔倾向于牺牲一些性能和表达力来换取Rust的简单性。他认为这不仅能简化编译器的实现,还能降低使用Rust的程序员的认知负担。虽然这可能导致Rust运行速度略慢,但霍尔认为这是值得的。然而,团队更倾向于追求类似C++的高性能,致力于实现"零成本抽象"。

霍尔强烈反对"零成本抽象"这一理念,认为它限制了Rust语言的设计空间。他主张大多数抽象都伴随着成本和权衡。霍尔更愿意用许多小而恒定的性能成本来换取一个抽象更简单、功能更强大的Rust语言。

2012年1月,在霍尔多次讨论中败下阵来后,Rust发布了预览版(pre-alpha)。

随着拥有软件类型系统博士学位的成员加入Rust核心团队,Rust的类型系统在0.2、0.3和0.4版本之间经历了重大变革。

2012年3月发布的0.2版本首次引入了类的概念。

仅4个月后,0.3版本通过引入接口,增加了析构函数和多态性支持。

又过了3个月,0.4版本引入了trait作为继承机制。接口被整合到trait中,不再独立存在。类则被结构体及其实现所取代。

在此期间,Rust通过所有权系统实现的内存安全管理逐步得到加强,有效防范了内存错误。

2012年,Mozilla与三星公司展开合作,启动了名为Servo的实验性Web浏览器渲染引擎项目。该项目主要采用Rust语言编写。

与此同时,C/C++社区也在积极发展。2011年,C++11和C11相继问世。C++11的发布尤为重要,它标志着现代C++时代的开启。这两次更新确实提升了C/C++的内存安全性,但值得注意的是,这些安全特性仍然不是必选项。

4

2013年中,经历多次讨论失利后,担任了3年"仁慈老大"的霍尔在婚姻、健康和工作的重压下濒临崩溃。

2017年,霍尔在回复 reddit.com 网友的帖子时,如此描述了当年的困境:"2013年中期,我已耗尽了情感能量,无法继续有效地担任 Rust 语言项目的技术主管。那时我正处于离婚手续的尾声,还在手术后恢复期。那绝非我人生中的高光时刻。"

霍尔决定暂时休息。他离开了 Rust 团队,在 Mozilla 内部花了一年时间从事低调且交付时间不太紧迫的项目。他先是加入 Firefox-on-Android 团队负责测试自动化,后来又转向 WiFi 和蜂窝地理定位服务团队。

2014年,霍尔最终离开了 Mozilla。此后,他在与 Rust 完全无关的支付网络公司 Stellar 工作了一年半,专注于分布式交易处理器的开发。

2016年初,霍尔接到了苹果公司的一个电话,对方表示他们正在寻找人才协助开发 Swift 语言。这并非领导职位,这一点正合霍尔的心意。于是,他加入了苹果公司。

2019年,霍尔离开了 Swift 语言开发团队。

在2023年5月30日发表的博客中,霍尔详细描述了他在2013年所承受的工作压力。

压力与情感负担。从2009年到2013年担任技术负责人期间,霍尔几乎达到了情感和心理的极限。随着Rust项目知名度和关注度的提高,压力也随之攀升。领导一个快速成长且备受瞩目的项目带来的压力最终变得难以承受。这种情感耗竭在领导角色中并不罕见,尤其是在像Rust这样由志愿者驱动的项目中。

冲突回避与内部紧张。霍尔观察到Rust治理中的一个模式:内部冲突管理不善,常被回避,却以更具破坏性的方式重新浮现。这种未解决的紧张循环不仅导致他自己,也使许多贡献者精疲力竭。项目参与者倾向于避免冲突,但问题并未消失,反而积累并最终导致关键人员离开。霍尔承认自己也有避免冲突的倾向,这加剧了直面内部问题的难度。

正式治理结构的缺失。霍尔指出Rust缺乏处理冲突、决策和授权的正式结构。Rust的治理系统在Mozilla这个松散组织的环境中发展,而该环境并不强调正式的冲突解决机制。结果,当争议出现时,项目缺乏有效的解决方法,导致更多的挫折感和不专业行为。

社区压力。霍尔描述了Rust社区内部存在的一种"围困心态"。许多贡献者因对这门语言的热情而深度投入,将Rust视为一项全有或全无的事业。这种高度的情感投入虽然富有成效,但也使得妥协和缓解冲突变得困难。贡献者们全身心地投入项目,常常以牺牲个人健康为代价。霍尔反思道,这种围困心态(部分源于他自己的焦虑)导致许多人濒临精疲力竭的边缘。

不健康的工作文化。霍尔讨论了Rust项目中发展起来的不健康工作文化。许多贡献者将投入项目的时间等同于决策权,导致那些付出最多时间和精力的人主导了决策。这造成了一种局面,人们不是通过沟通来解决冲突,而是通过纯粹的坚持不懈来消耗对手。霍尔承认,这是一种糟糕且不可持续的决策方式。

管理技能的欠缺。霍尔坦言,他自己和大多数早期Rust贡献者都缺乏项目管理、冲突解决或调解等方面的经验或培训。缺乏专业的治理和管理知识加剧了Rust的内部冲突。这一问题因Mozilla(项目孵化地)在正式治理结构方面支持不足而变得更加严重。

"仁慈老大"角色与个性不符。霍尔解释说,成为"仁慈老大"从未是他的愿望,也不适合他的性格。他不喜欢成为焦点或承受压力,而持续需要做出决策和解决冲突的压力最终让他难以承受。这种角色与他性格之间的不匹配加剧了他的精疲力竭。

霍尔在这篇博客中全面讨论了程序员成为开源软件"仁慈老大"后面临的困境,为所有从技术岗位转向管理岗位的程序员提供了深刻的思考。

5

2013年,伴随着霍尔退出Rust语言的开发工作,Rust的类型系统继续完善。此时,团队发现之前设计的垃圾回收器已不再必要,于是将其移除。这一举措标志着Rust的所有权规则已经成熟到位。

2015年5月,Rust 终于发布了 1.0 版本,并承诺保持向后兼容。这一举措解决了程序员长期以来对 Rust 频繁变化的抱怨。值得注意的是,Rust 不太可能推出 2.0 版本。根据语义版本控制约定,2.0 版本意味着与之前的 1.x 版本不兼容。对于专注于构建系统级软件的程序员来说,这种代码不兼容的情况是难以接受的——就像没人愿意频繁更换房屋地基一样。

2020年8月,由于全球疫情引发的公司重组,Mozilla裁掉了全球1000名员工中的250名。其中,负责Servo项目的团队被解散。这一事件引发了对Rust未来的担忧,因为该团队中有多名Rust的活跃贡献者。

幸运的是,在接下来的一周内,Rust核心团队承认了裁员带来的严重影响,并宣布正在筹划成立Rust基金会。该基金会的首要目标是接管所有商标和域名,并承担相关费用的财务责任。2021年2月8日,五家科技巨头(AWS、华为、谷歌、微软和Mozilla)联合宣布Rust基金会正式成立。

在此期间,与内存安全相关的漏洞持续爆发。2014年,一个名为Heartbleed的严重漏洞引起了广泛关注。这个漏洞源自OpenSSL加密库中的一个缺陷,允许攻击者读取易受攻击版本软件的服务器内存。这可能导致敏感数据泄露,包括私钥、用户名、密码和加密信息。Heartbleed影响了全球数百万网站,由于许多系统长期未修补,其完全解决花费了数年时间。

OpenSSL在类Unix系统中广泛应用。Heartbleed漏洞起源于OpenSSL 1.0.1版本中引入的传输层安全(TLS)协议心跳扩展的C语言实现缺陷。这个扩展旨在无需重新协商即可保持TLS连接活跃。它通过在连接两端之间发送"心跳"请求实现,每个请求包含一小段数据负载(如"cat")和一个表示负载长度的字段。

受影响的OpenSSL版本中,C语言实现未能验证长度字段是否与实际负载大小匹配。攻击者可以利用这一点,构造一个声称长度很大(如500字符)但实际负载很小(如3字符"cat")的请求。

服务器接收到这种格式错误的请求时,会根据攻击者提供的长度(500字符)分配内存,但只填充实际负载("cat")。缓冲区剩余部分会包含服务器内存中紧随其后的数据,可能暴露敏感信息如密码、私钥或会话cookie。每次心跳请求可能泄露高达64KB的服务器内存数据。

由于该漏洞允许任意读取内存,攻击者可能访问服务器上的机密数据,甚至获取用于加密安全通信的密钥。这对使用OpenSSL的高流量网络服务器尤其危险,可能导致大规模敏感信息泄露。

简而言之,Heartbleed利用了OpenSSL心跳扩展中缺少边界检查导致的缓冲区过度读取漏洞。这使攻击者能够获取非预期的内存块,从而可能泄露敏感信息。

这期间,各家互联网巨头也相继发布了安全漏洞报告。2019年,Mozilla报告称"34个严重或高风险漏洞中,高达32个与内存相关"。谷歌也指出,Chromium项目发现约70%的严重安全漏洞是内存安全问题。微软在一篇博客中表示,他们每年发现的通用漏洞中,约70%仍与内存安全有关。三年后,2022年4月19日,谷歌的Project Zero团队分析了攻击者利用的"零日漏洞"后发现:"在当年的58个零日漏洞中,39个(即67%)是内存损坏漏洞。"

这段时间,C++相继在2014年发布了C++14,在2017年发布了C++17,在2020年发布了C++20,并在2023年通过了C++23标准。与以往一样,内存安全仍然不是C++的必选项。

6

使用编程语言的程序员,对Rust语言的态度是怎样的呢?

2016年,在Rust 1.0推出后的第一年,Rust在Stack Overflow的年度调查中首次名列"最受喜爱(most loved)的编程语言"榜首,并连续9年(从2016年到2024年)保持这一头衔。

值得注意的是,从2023年开始,这一头衔更名为“最受推崇(most admired)的编程语言”。这一殊荣反映了Rust在开发者中日益增长的受欢迎程度,他们一致表示喜欢使用这门语言并希望继续使用它。

程序员为何这么喜欢Rust?为了解答这个问题,霍尔在2016年12月28日发表了一篇“Rust主要是安全”博客,说安全性是Rust在系统编程中的主要目标和价值,特别是它解决了安全并发问题,正如Rust语言开发核心团队成员亚伦·图伦(Aaron Turon)在2015年博客中所提到的“无畏并发”。但另一位核心团队成员史蒂夫·克拉布尼克(Steve Klabnik)却不大同意这个观点。

克拉布尼克在2013年前是Ruby和Ruby on Rails的开源项目贡献者。2013年后,他转向Rust。2014年,他加入Rust核心团队,成为Rust文档团队的负责人。他与Crates.io团队成员卡罗尔·尼科尔斯(Carol Nichols)在2019年共同撰写了《Rust编程语言》一书,并在2023年推出了第二版。

克拉布尼克在霍尔发表"Rust主要是安全"博客的同一天,也发表了一篇名为"Rust超越了安全"的文章。他认为Rust社区过分强调技术细节(如安全性和底层编程),而忽视了向Rust用户——即使用Rust的程序员——传达Rust真正能解决的问题。克拉布尼克呼吁Rust用户关注Rust的实际应用场景,分享Rust如何帮助他们解决编程难题,从而更有效地推广Rust。

克拉布尼克的用户导向思维,确实很高明。那到底Rust能帮用户解决什么问题呢?下面是小吾的回答。

从马斯洛的需求层次理论来看,Rust语言通过将内存安全作为必选项,为系统级软件的开发者和用户提供了更高层次的安全感和满足感。这种安全感不仅仅是技术层面的,更是心理和情感层面的重要需求。

  1. 生理需求:在软件开发的背景下,这可以理解为基本的开发环境和工具。C/C++和Rust都能满足这一层次的需求。
  2. 安全需求:Rust的内存安全机制直接满足了开发者和用户的安全需求。通过在编译时强制执行内存安全规则,Rust大大减少了内存相关的漏洞,为开发者提供了一个更安全的工作环境,同时也为用户提供了更可靠的软件产品。这种安全感是C/C++难以企及的。
  3. 归属需求:Rust的安全特性让开发者能够更自信地参与大型项目和开源社区,增强了团队协作和社区归属感。相比之下,C/C++项目中的内存安全问题可能会造成团队内部的紧张关系和责任归咎。
  4. 尊重需求:使用Rust开发的安全可靠软件能够赢得同行和用户的认可和尊重。开发者可以因为创造出高质量、低漏洞的代码而获得专业上的肯定,这种成就感是满足尊重需求的重要方式。
  5. 自我实现需求:Rust的安全特性让开发者能够专注于解决更高层次的问题和创新,而不是被低级的内存错误所困扰。这使得开发者能够更好地发挥创造力,实现自我价值,达到自我实现的需求。

Rust将内存安全作为必选项,不仅提供了技术层面的保障,更满足了开发者和用户在心理和情感上的多层次需求。这种全方位的安全感和满足感,是C/C++这样将内存安全仅作为可选项的语言难以企及的。Rust的方案体现了对人性需求的深刻理解,这也解释了为什么它能在开发者社区中获得如此高的评价和喜爱度。

7

2015年,Dropbox公司在启动Diskotech存储服务项目时,选择了Rust作为编程语言,而非之前常用的Go。这标志着Rust语言开始在互联网巨头中圈粉了。

国内常用"BAT"指代互联网大厂,而帕特里克·麦肯齐(Patrick McKenzie)则创造了"AppAmaGooBookSoft"来代表美国五大互联网巨头:苹果、亚马逊、谷歌、Facebook和微软。从2015年Rust 1.0发布开始,除苹果外,其他四家公司都陆续成为了Rust的忠实用户。虽然苹果公司未直接采用Rust,但他们开发的Swift语言因2016至2019年间聘请了霍尔参与设计,也带有些许Rust的特色。

2016年,Facebook在开发大规模源代码控制系统Mononoke时,率先选择使用Rust而非C++,主要考虑到可靠性。Mononoke旨在提升Mercurial源代码控制系统的性能,Facebook用它管理庞大的代码库。Mononoke的优势在于提高了可靠性和性能,满足数千名开发者的需求。Rust的内存安全和并发模型成为理想选择,减少了潜在错误,增强了系统稳健性。Mononoke特别适用于需要高度可扩展性和性能的版本控制系统环境。

2018年,微软在实现Azure IoT Edge时,用Rust开发了部分组件。Azure IoT Edge是Microsoft Azure IoT团队的开源跨平台软件项目,旨在解决从云到本地网络边缘的计算分配问题。系统中的安全守护进程用Rust编写,确保了Azure IoT Edge运行时与硬件组件(如TPM和HSM)间的安全通信。选择Rust是因为其内存安全性、高性能以及无运行时开销,非常适合安全且资源受限的环境。Azure IoT Edge特别适用于需要安全和可扩展边缘计算的场景。

2019年,AWS开源了主要用Rust编写的虚拟化解决方案Firecracker。这是AWS开发的轻量级虚拟化技术,专为无服务器计算和容器工作负载设计。它创建微型虚拟机(microVMs),提供传统虚拟机的安全性和隔离性,同时具备容器的速度和资源效率。Firecracker利用Rust构建,确保内存安全和高性能。它被用于AWS的Lambda和Fargate等服务中,提供快速启动、低内存开销和高可扩展性,非常适合对性能和安全性要求极高的云环境。

2021年5月25日,谷歌首次发布新操作系统Fuchsia,其关键代码用Rust编写。与Android和ChromeOS不同,Fuchsia基于名为Zircon的自定义微内核。Fuchsia设计注重灵活性,可在各种设备上运行,从智能家居中枢到智能手机。它的主要优势包括提高安全性、可扩展性,以及通过Flutter(一个UI工具包)实现跨平台开发。Fuchsia使用多种编程语言,其中Rust扮演关键角色,通过内存管理功能确保系统安全。它适用于嵌入式系统和消费类设备,如智能显示器。

2023年1月,谷歌宣布支持在Chromium中使用第三方Rust库。

2024年9月25日,The Hacker News发表文章,报道通过将 Rust 等内存安全语言引入 Android 开发,谷歌实现了 Android 系统中内存安全漏洞从76%减少到24%,在六年内下降了68%。。

随着这四大互联网巨头的背书,Rust确实如克拉布尼克在2016年那次关于Rust历史的分享中所预言:2016年是Rust开始进入各大互联网巨头的生产环境的起点。

8

Rust在各大互联网巨头数据中心生产环境中的广泛应用,其影响逐步扩散至C和C++相关社区,以及美国政府部门。

Linux社区(主要由C语言实现)也开始拥抱Rust。

2020年,米格尔·奥赫达(Miguel Ojeda)发起了"Rust for Linux"项目,旨在将Rust编程语言引入Linux内核。该项目的主要目标是提高内核组件(如驱动程序)的内存安全性并减少错误。Rust的特性,尤其是其防止内存错误(如缓冲区溢出和空指针解引用)的能力,使其成为增强Linux内核安全性和可靠性的理想选择。

2022年12月,"Rust for Linux"项目为Linux添加了初步的Rust支持。Rust由此成为继C和汇编语言之后,第三个在Linux内核开发中得到支持的语言。

2023年12月,首个用Rust编写的驱动程序被Linux接受,并在6.8.34版本中发布。

C++社区的反应如何?

2021年10月,美国国家标准与技术研究所(NIST)发布了"软件开发者验证的最低标准指南"。该指南指出:"某些语言,如C和C++,缺乏内存安全性。即使是微小的内存访问错误也可能导致严重后果,包括权限提升、拒绝服务、数据损坏或数据泄露等漏洞。"

2022年11月,美国国家安全局(NSA)发表了一篇关于软件内存安全的文章。文章明确指出C/C++容易引发内存漏洞,而包括Rust在内的9种语言在内存管理方面更为安全。

2023年1月15日,面对美国政府两个部门(NIST和NSA)公开不建议使用内存不安全的C/C++的压力,C++语言的创始人比雅内·斯特劳斯特鲁普(Bjarne Stroustrup)在一份声明中表达了对C++安全性的看法。这份由斯特劳斯特鲁普共同撰写的新声明呼吁考虑改变C++编程语言本身以解决内存安全问题。声明表示:"我们现在支持这样的观点,即安全性的改进不仅需要在工具中实现,还需要在语言、编译器和库中体现。"该声明仍然支持C++长期以来倡导的使用调试工具来确保安全的方法,同时也强调"推动工具实现更全面的分析,以识别人类难以察觉的安全问题"。

2024年9月12日,C++联盟与著名工程师肖恩·巴克斯特(Sean Baxter)建立合作伙伴关系,共同开发安全C++扩展提案。安全C++是C++的一个扩展,旨在提高内存安全性,同时保持与现有代码的兼容性。它引入了借用检查、显式变异等概念,并禁止传统C++程序中常见的未定义行为,创建了一个C++安全子集。这个子集采用了类似Rust安全模型的模式,如仿射类型(常见于函数式编程语言,类似于Rust中对值拥有唯一所有权的变量类型)和显式安全机制。尽管安全C++融入了类似Rust的特性来增强内存安全性,但它通过构建在C++之上并提供与不安全代码的可选互操作性来保持其独特性。

Rust将内存安全从C/C++的可选特性转变为必选项,为系统级软件开发者和用户带来前所未有的安全感。统治系统级软件开发市场半个世纪之久的C/C++,竟被诞生仅9年的Rust如此撼动!

9

2019年离开Swift语言开发团队之后,霍尔专注于追求个人兴趣。他最喜欢的消遣是在住处附近的海边漫步。此外,他还享受午睡、沉浸于历史书籍、与朋友外出游玩,以及反复欣赏同一批80年代的经典电影——仅十几部,却百看不厌。

近年来,霍尔偶尔在博客中谈及Rust。尽管他已离开Rust语言开发团队超过十年,且对Rust的某些设计持不同意见,但他在2023年6月4日的博文《我想要的Rust没有未来》中写道:"别误会。我喜欢Rust目前的成果。它很出色。我很高兴看到有一个可行的C++替代品,特别是一个被普遍认为是规范的、适合日常使用的合理选择。我使用Rust,并且乐意优先选择它而非C++。"

在这篇博文的末尾,霍尔特意在心情一栏写上"愉悦"。这表明他已经与十年前那个因工作压力濒临崩溃的自己和解了——他不仅接受了,甚至欣赏起这个由让他在讨论中败下阵来的团队所开发的、不完全符合他最初设想的Rust。

2023年3月23日,一群看似低调却身怀绝技的黑客云集温哥华,参加了在霍尔居住地举办的Pwn2Own黑客大赛。法国渗透测试公司Synacktiv的研究人员在不到两分钟内,成功在行驶中的特斯拉Model 3上打开了前备箱和车门。这一惊人壮举为他们赢得了一辆全新的特斯拉Model 3和10万美元现金奖励。

这短短两分钟里,黑客巧妙利用了特斯拉电动车的两个关键漏洞。

首先是特斯拉能源管理系统的TOCTTOU(Time-of-Check-to-Time-of-Use,检查时间与使用时间差异)漏洞。黑客利用系统检查与实际操作之间的时间差,在Model 3行驶时打开了车门和前备箱——这本应是不可能的操作。

其次是特斯拉蓝牙芯片中的堆溢出和越界写入漏洞。黑客从这个看似微不足道的入口,通过精心设计的堆溢出和越界写入,逐步获取了对信息娱乐系统的访问权限,最终突破系统边界,深入控制了车辆核心功能。

面对这两个令人瞠目的漏洞,Rust爱好者们不禁兴奋地问:这不正是Rust大显身手的绝佳机会吗?

确实,Rust凭借其出色的并发安全特性和严格的借用检查机制,有望有效防范类似TOCTTOU攻击中的时间差问题。而对于第二个漏洞,Rust独特的所有权系统通过编译时的内存访问检查,可以从根本上杜绝堆溢出和越界写入等漏洞,这在应对蓝牙芯片漏洞时尤为关键。

遗憾的是,Rust目前还无法直接参与其中,原因在于它尚未符合ISO 26262标准——这一汽车行业功能安全的国际标准严格规定了安全关键系统的开发要求。但好消息是,Ferrous Systems公司正在积极开发符合标准要求的安全关键Rust语言子集。一旦成功,Rust很可能成为汽车行业和其他安全关键应用中开发安全系统的首选语言。

想象一下,当那一天来临,你在街头看到电动车飞驰而过,或是在使用和编写系统级软件时,是否会因为Rust的内存安全必选项而倍感安心?这种由语言本身带来的安全感,或许将彻底改变我们对技术的信任度。

  • End -

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档