程序猿界的强迫症语言为何还是做不到100%安全?

2019-05-05 19:38:3216151人阅读


五一小长假归来首日,我们来继续回顾2018年DEF CON CHINA Beta中的精彩演讲,而这是系列回顾计划的第四篇。

毫无疑问,你我都是互联网世界的资深用户,各种应用驾轻就熟,各种招术也应对自如。不过,你我也都知道,不管互联网世界的表象多么炫酷光鲜,其底层都是一行行朴素低调的代码。这些代码成就了互联网的强大,也带来了互联网的脆弱——小小一个漏洞,瘫掉全球互联网,并非是天方夜谭。

一直以来,人们始终在摸索更安全的编程语言,并似乎已经取得了一些成果,比如Rust。但事实,也许并不完全尽如人意。 

在DEF CON CHINA Beta上,百度安全的研究团队对外讲解并展示了他们的最新研究成果,“When Memory-Safe Languages Become Unsafe”,中文名为“当内存安全变得不再安全”。

需要提前说明的是,这将是一个从内存不安全、到内存安全、再到内存仍旧不安全的故事。而在开始讨论内存安全为何不再安全之前,我们先来聊聊什么是内存安全,以及其“招牌语言”Rust。

 

1.png

 

而讲到Rust,就不得不提到它的前辈C/C++语言。作为时至今日都是在全球范围内应用最广泛的编程语言,C/C++可谓奠定了整个互联网世界的基石,但是,随着互联网的迅速普及和AI时代万物互联的到来,这个诞生于上世纪70年代、漏洞危害频发的“古老语言”也备受质疑——部分基础逻辑机制的缺陷和含混,让其被认为是内存不安全的语言。

举个例子,你我大多应该都是或曾是Windows或Microsoft Office的用户,对于其隔三差五就各种打补丁可谓再熟悉不过。根据微软安全工程师Matt Miller今年2月在以色列举行的安全会议BlueHat上对外透露的数据,在过去的12年中,微软为旗下这些产品所修复的漏洞,70%都是内存安全问题。而造成这一高比例的很大一部分原因,正是因为其起初大多是使用C/C++语言编写的。 

2015年5月,主角登场。经过长达6年的基础研发,内存安全的Rust 1.0版本正式发布,并迅速获得市场认可。

 

2.png

从2016至2018年,Rust连续三年在Stack Overflow开发者调查中获评“最受喜爱编程语言”

那么,相比C/C+,Rust做对了什么呢?

简言之,Rust是个处女座专属语言强迫症加持。

例1:Rust处女座的“所有权机制”

在现实生活中,你一定遇到过处女座的妹子,她用的水杯一定要放在桌子左上角的圆圈里;她用过的文件一定归档收好,电脑桌面空空如也。她借给你一本书,你必须在三天之后下午四点十六分送还给她。

Rust在内存管理上,就是这样的处女座。

如果这段内存属于A进程,那么它就一直属于A进程,如果B进程来借这段内存,那么它就必须按时归还。如果不归还,整个程序都会卡在原地,无法继续。

如果A进程不想要这段内存了,它就要决定把它过户给B进程,或者直接把它释放掉。所以,这段内存要么属于A,要么属于B,要么被系统回收。这样严密的逻辑,会有模棱两可的情况出现?不存在的。

而在C/C++语言中,情况就乱得多,各种借调和归还都没有明确的制度保证。也正是基于这种机制问题,十几年来黑客们研究出了很多类型的漏洞。

 

例2:Rust处女座的“生命周期机制”

你记不记得,在我们身边有一种奇葩的送礼Style:中秋节送的月饼,A送给B,B送给C,C送给D,等到D准备吃的时候,发现已经过期了——这就展现了一个经典的Bug,你对月饼的使用周期已经超过了月饼的生命周期。

在编程的世界中,存在着同样的问题。

一个内存指针本身是有生命周期的,它的生命周期由编译器指定。这个时候,如果有人获取了同为这段内存上的另一个指针,那么Rust就会自动规定这个指针的生命周期要小于之前的那个,保证了一套完整的内存生命流程。

就好像一本书,最开始在小A家的书架上,后来小A借给了小B,小B又借给了小C,但是在归还的时候,会有警察叔叔专门监督着小C先还给小B,再由小B还给小A,最后由小A放回自家的书架。这里的“警察叔叔”,就是Rust系统的逻辑机制。

你可能会问,这本书本来就是小A的,如果让小C直接还给小A,不是更简单吗?对不起,我只能说你还是不够了解处女座。在Rust的世界里,规矩就是规矩。

事实上,Rust的“生命周期机制”杜绝了C/C++中一个重要缺陷,那就是Double Free。在C/C++语言中,由于没有严格的管理,会发生一个内存被两次释放的“神操作”。每当这时,系统就会因为这个“非定义行为”而进入神经错乱状态。

 

P.S. 以上关于“处女座专属语言”的内容,主要节选自浅黑科技“一把锁的传奇:从OpenSSL到MesaLink”一文,作者为史中,更多前生今世请参阅原文

由此,相较于C/C++语言,很处女座很强迫症的Rust所输出的程序都很规矩,在安全性上的优势也显而易见,而其也被认为是内存安全的语言。

 

从不安全到安全,故事本应到此结束。但是,你还记得我们在开篇时提的那个醒吗?这将是一个从内存不安全、到内存安全、再到内存仍旧不安全的故事。而至此,我们一直在阐述的是从内存不安全到内存安全的曲折历程,那么,为何内存安全的Rust还是不安全呢?这也是在DEF CON CHINA Beta中,百度安全的研究团队所带来的分享主题。

篇幅所限,我们在这里省略复杂的测试和推导过程,只说结论。

百度安全的研究团队收集并分析了10000个使用Rust编写的程序或库,发现几乎所有Rust程序都依赖libc库,且至少25%的Rust库都依赖其它C/C++的库。这些库破坏了Rust的内存安全特性,并暴露了一些潜在的威胁。

 

P.P.S libc是Linux下的ANSI C的函数库,ANSI C是基本的C语言函数库,包含了C语言最基本的库函数。

 

同时,大多数开发者并不知道程序使用了这些不安全的C/C++库,也没有注意这些威胁的存在。而由于一些静态链接的C/C++库的存在,引起了库依赖的碎片化,也使得大规模的更新升级更有挑战。

换句话说,假设Rust就是你家楼下一家干净卫生的连锁快餐店,它保证了它的食材、烹饪流程、餐具都是安全的,所以由它自制的汉堡、鸡块和薯条也都是安全的,由Rust编写的程序也是这样。但是,就像Rust一样,这也是家有个性的快餐店,只不过Rust是处女座,它是不卖不配不送番茄酱。可热爱番茄酱的你,在汉堡里要加在鸡块里要加在薯条里也要加,于是在下楼吃饭时你决定,自带番茄酱。

 

接下来,你翻箱倒柜终于在你家某个落灰的角落里翻出一瓶存放了许久已经过期的番茄酱,但显然大喜过望的你并未注意到这一点。直到当次日胃感不适时,才会想起来回头看看那瓶番茄酱的保质期。

的确,由于Rust的强迫症特质和应用时间较短,很多开发者“偷懒”拿出了以前用C/C++编写的“旧有片段”——就像过期的番茄酱,牵连了新鲜的汉堡、鸡块和薯条。

那么,如果这家快餐店统一采购一批市场上现成的番茄酱,是否就能避免由消费者自带番茄酱所可能存在的隐患呢?答案仍然是不确定的,因为快餐店显然无法保证这些市售番茄酱的100%安全。放在Rust身上,情况也是这样的。

 

来自百度安全近一步的研究表明,即使完全使用内存安全语言做开发,内存安全问题依然存在。

比如,Rust允许开发者使用“unsafe”关键字编写非内存安全的代码以绕过编译器的限制。但是,一些库使用了这些“unsafe”代码,并把这些代码重导出为“安全”的函数给其它开发者使用。其他开发者使用这些“安全”的函数的时候并不知道“非内存安全”代码的存在,从而埋下了内存安全的隐患。当然,也许你会说至少“非内存安全的代码”需要使用“unsafe”关键字显式的调用,开发者可以看到这些信息。但是,如果这些不安全的代码出现在已经被封装的库中呢?

 

实际上,所谓只要用内存安全语言编写的程序就能100%保证类型安全、内存安全以及线程安全,是一种错觉。

那么,我们应该如何更安全的利用Rust及Rust中无法规避的“unsafe”代码?这就要提到百度安全在Rust SGX SDK项目中提出的混合代码内存安全架构三原则:

 

1. 隔离并模块化由非内存安全代码编写的组件,并最小化其代码量。

2. 由非内存安全代码编写的组件不应减弱安全模块的安全性,尤其是公共API和公共数据结构。 

3. 由非内存安全代码编写的组件需清晰可辨识并且易于更新。

 

换句话说,程序的核心部分需均由Rust编写,只有对外接口部分才可使用C/C++;且外部数据不能接触程序核心的数据模块,需隔离管理。同时,对于上述代码和管理规则,需有明晰的规范和注解。

 

基于此原则,百度安全为蓬勃发展的Rust生态做了以下几件事:

首先,MesaTEE,百度安全与英特尔联手打造的全球首个内存安全的可信计算架构。

 

8.png

2018年9月,百度首席安全科学家韦韬博士与英特尔副总裁Lorie Wigle共同宣布推出MesaTEE

 

基于百度安全首创的高级内存安全技术模型Hybrid Memory Safety(HMS)和英特尔软件防护扩展Software Guard Extensions(Intel SGX),MesaTEE实现了云上数据的完整性和保密性的芯片级安全保障,且不会导致性能和功能的显著降级。同时,通过允许用户对执行环境进行远程验证,确保远程执行环境符合预期。而以上,均兼具内存安全所带来的不可绕过性,使其能够抵御绝大多数的攻击,达成性能与安全的统一。 

在今年3月,MesaTEE还亮相已有24年历史的美国RSA大会,展示了在公有云、区块链等各类复杂场景中的对隐私数据和AI模型的强大保护能力。

第二,MesaLock Linux,墨安锁,一个开源的通用Linux发行版本。

其目标是用Rust、Go等内存安全语言编写用户空间应用(User Space Applications),在用户空间中逐步消除高危的内存安全漏洞。即在保留Linux硬件兼容性的前提下,极大降低整个系统的攻击面,并使剩余的攻击面可审计、可收敛,实质性地提升Linux生态的安全性。

 

9.png

MesaLock Linux LOGO的灵感来源于中国古代的孔明锁

 

第三,MesaLink,墨安链,旨在为智能终端提供安全可信网络通信的下一代传输层安全库。 

其同样使用内存安全的Rust语言编写,在语言层面最小化内存漏洞的风险,从根本上杜绝类似OpenSSL“心脏出血”漏洞(Heartbleed)的出现。同时,兼容OpenSSL API,方便已有应用迁移。

2018年11月,MesaLink首次登陆Rust社区两大核心会议之一的RustFest,并作为开源的“七种武器”之一,对外展示了百度安全在Rust FFI领域(Foreign Function Interface,Rust与非内存安全语言之间的交互)引领世界的研发思路与实践成果。

 

10.png

百度安全MesaLink亮相RustFest

 

秉承有AI,更安全的使命,百度安全始终致力于在全面覆盖百度各种复杂业务场景的同时,为生态合作伙伴提供技术支点及完善的产品解决方案。Rust作为一个可能在未来互联网世界得到最广泛使用的编程语言,对于安全性的研究自然也是责任所在。这不仅关乎于整个行业的安全和发展,也关乎于助力中国更多掌握互联网底层技术的话语权。而从MesaTEE到MesaLock Linux再到MesaLink,在Rust的具体应用层面,百度安全已经走在前列。

 

最后,我们回到即将揭幕的DEF CON CHINA 1.0,重要进度表再来强调一遍:

 

2019年5月31日至6月2日,DEF CON CHINA 1.0,锁定北京751D·PARK。

 

DEF CON CHINA 1.0门票已正式开售,点击文末“阅读原文”,登陆DEF CON CHINA官方网站,直通购票通道。

 


 

 


0
现金券
0
兑换券
立即领取
领取成功