对于工程师来说,C/C++语言是最常用的编程语言之一,它是一种高效、简洁、灵活的编程语言,尤其在嵌入式、单片机领域,它创造了许多奇迹,包括智能手机、家用电器、汽车或是医疗设备。
但每每提及“安全”问题时,大部分人便将C/C++划在围城之外。12月6日,美国网络安全和基础设施局 (CISA)联合美国国家安全局(NSA)、美国联邦调查局 (FBI)及澳大利亚、加拿大、英国和新西兰的网络安全机构发布《内存安全路线图指南》,点名C/C++存在内存安全漏洞,软件开发商应放弃使用,改用C#、Rust、Go、Java、Python和Swift等内存安全的编程语言 (MSL)。
那么,这究竟是什么情况,我们还能安心使用C/C++吗?
C/C++的黑暗面
内存安全漏洞(CWE-1399:综合分类:内存安全)是一类影响在编程语言中以意外方式访问、写入、分配或释放内存的漏洞。
透过漏洞,恶意行为者能够非法访问数据、损坏数据或运行任意恶意代码。例如,恶意行为者可能会向应用程序发送精心制作的有效载荷,从而破坏应用程序的内存,然后使其运行恶意软件。或者,恶意参与者可以发送包含恶意软件的格式错误的映像文件,以在受害者系统上创建交互式外壳。如果参与者可以以这种方式执行任意代码,参与者可以获得对运行该软件的帐户的控制权。
事实上,早在去年9月,微软CTO Mark Russinovichi就在其社交账号上发布动态称,开发人员是时候停止使用C/C++来启动新项目,建议在使用non-GC语言的场景中使用Rust。
2022年底,NSA也曾在报告《Software Memory Safety》中呼吁过放弃C/C++,彼时他们表示,C/C++已被证实是内存安全漏洞的温床,它们在内存管理方面提供了很大自由度和灵活性,用这种语言开发的应用程序安全性很大程度上需要依赖程序员的测试、检测环节,与此同时,他们还鼓励各组织将编程语言从C/C++转向C#、Rust、Go、Java或Ruby等编程语言。
今年1月,C/C++的问题甚至引起了拥有87年历史的《消费者报告》的关注,表明了对这个问题的认识,彼时报告中称,内存安全是复杂的话题,据估计,至少有65%的安全漏洞是内存错误的结果。
此次报告中则指出,这个几十年前就首次发现的缺陷仍然是当前恶意行为者经常利用的常见漏洞,以破坏应用程序和系统。比如说:
-
微软在2019年一次会议上表示,自2006年至2018年,70%的漏洞是由内存安全问题引起的;
-
在GoogleChromium项目中发现的漏洞中,约70%是内存安全漏洞;
-
在对Mozilla漏洞的分析中,34个严重/高度错误中有32个是内存安全漏洞;
-
根据Google Project Zero团队的分析,2021年有67%的零日漏洞是内存安全漏洞。
其实C/C++的这种漏洞并非不可控的,许多软件制造商投资于开发人员的培训计划。许多这些培训计划包括旨在减少由这些语言产生的内存不安全漏洞的流行率的策略。此外,还有许多商业和工业贸易协会的培训计划。此外,各种组织和大学提供培训和专业证书,以证明在C和C++安全编码实践的知识。
虽然培训可以减少编码员可能引入的漏洞数量,但考虑到内存安全缺陷的普遍性内存安全漏洞仍然会出现,这几乎是不可避免的。即使是最有经验的开发人员编写的bug也会引入显著的漏洞。培训应该是一个组织实现更健壮的技术控制(如内存安全语言)的桥梁。
许多公司针对这种漏洞,进行了许多优化。很多科技公司引入了代码覆盖测试、安全编码准则、Fuzzing 测试软件及开发者使用了静态应用程序安全测试(SAST)和动态应用程序安全测试(DAST)工具来查找各种软件的内存安全漏洞。比如说,C++社区一直在考虑向后兼容性、内存安全默认值和基础语言的其他优先级之间的平衡;苹果修改了iBoot system中使用的C编译器工具链,以缓解内存和键入安全问题;微软早些年还开源了一个更安全的C语言版本Checked C,在C中添加静态和动态检查,以检测或防止常见的编程错误;Google打造了一款 C++ 的继任者Carbon,针对现有代码的C++内存安全采取了改进措施。
硬件厂商,也在积极开发使用硬件支持内存保护。比如说,美国SRI International和剑桥大学的联合研究CHERI项目,为现有的芯片架构增加了新的功能;英国政府的数字安全设计(DSBD)计划汇集7000万英镑的政府资金和1.17亿英镑的工业联合投资开发技术;2022年,Arm公司探讨了其实验性Morello Program及CHERI架构实现原理,希望借此解决系统攻击中常被利用的一系列内存访问漏洞;而后,微软也参与了CHERI研发的相关工作。
当然,即便厂商已经投入大量心力避免漏洞,但结果依然不容乐观,而这正是CISA、NSA、FBI反驳使用C/C++的根本原因,而报告中,则推荐了C#、Rust、Go、Java、Python和Swift等几个编程语言。
安全性不等于内存安全
面对市场传言,C++之父Bjarne Stroustrup并没有选择沉默,而是在今年多次回击。
其中,最具代表性的就是其在2月发布的《Think seriously about“safety”;then do something sensible about it》(认真考虑“安全”,然后采取一些明智的措施”)一篇文章。
文章中,Bjarne表示,很多人的焦点都放在C/C++的弱点上,但实际这些缺陷是完全可以避免的。首先,要声明的是,C和C++根本就是天壤之别的两种语言,请不要混为一谈。C++能更加直接的表达程序员的想法,NSA完全忽略了C++在30年依赖的进步,并将C与C++混为一谈,这让人深表遗憾。
C++正引入更多特性,变得越来越安全,合格的C++程序员可以写出安全性可以与Rust媲美的程序。忽视安全问题会伤害C++社区的大部分成员,并破坏我们为改进C++所做的许多其他工作。专注于安全也是如此。
除此之外,“安全”的定义并不只有一个,我们可以通过编程风格、库的组合以及静态分析来实现各种各样的安全。NSA对“安全”的概念仅限于内存安全,而忽略了一门语言可能被用来违反某种形式的安全保障和十几种其他方式。
不是每个人都把“安全”看得高于一切。比如,在性能是主要关注点的应用程序域中,规则中允许仅在需要应用时保证安全,并在需要时使用最喜欢的调优技术。
目前世界上有数百万C++程序员与数十亿行C++代码,被应用在包括航空航天、医疗仪器、人工智能/机器学习、知识图谱、生物医学及高能物理等领域。据我所知,在发布报告前,没有一位专家向C++标准委员会进行过咨询,所谓“明智的做法”是什么,建议列出一个明确的清单。
1月中旬,官方C++“指导小组”发布了一份声明,解决了人们对C++安全性的担忧。虽然许多语言现在都支持“基本类型安全”,即确保变量只访问由其数据类型明确定义的内存部分,但C++一直难以提供类似的保证。>>查看全文
|