聊聊开源软件的安全问题

HBO的神剧《硅谷》是少见的以IT人为背景的情景喜剧,去年我花了几个月时间把全剧刷了一遍。从这部十分荒诞的肥皂剧中,我看到了很多IT大佬的身影,甚至也看到了我自己年轻时的一些影子,等有空的时候,我会写一篇文章和大家分享一下观影体会。

最近我只要遇到有关黑客,网络安全的事情,眼前就会浮现出《硅谷》里的那个能黑一切的Gilfoyle。有些人可能以为电视剧里无所不能黑的Gilfoyle只是夸张的演绎,而作为一个在IT领域摸爬滚打了30年的我可以负责任的说,历史上那些传奇黑客的传说大多数是真实的。

在当前这场美国、俄罗斯等黑客强国与我们的网络安全领域的攻防战中,我们在相关技术上处于相对弱势是绝对的事实。恐怕这也是近些年国家越来越重视网络安全的主要原因,既然技术上不如人,那么我们尽可能把篱笆扎紧,把家看好。

开源软件自从90年代初开始兴起后,立即体现出了全方位的优势,开源软件让很多关键基础软件领域的研发成本大大降低了,也加速了基础软件领域的发展。

目前开源软件在全球IT生态中已经占据主导地位,同样对我国的影响也是巨大的。据截至2020年底的不完全统计,在我国使用开源技术的企业占比大约在88%,开源数据库在国内企业中的使用比例也接近六成。

实际上大量的商用软件中也使用了大量的开源代码,2018年的CPU Meltdown和Spectre漏洞爆出来的时候,几乎所有主流CPU厂商都中招了。凡是使用2010年以后的英特尔、AMD和ARM架构产品(苹果、高通、三星、华为、英伟达等)的厂商包括服务器、云端、超级计算机甚至一些银行和军队,通通难逃漏洞波及。另外,英伟达的GPU包括GeForce、Quadro、Tesla等也受到的影响。为什么会这样呢?这是因为这些产品中都使用了同一个开源代码,这些漏洞就是在开源代码中存在的。

很多朋友可能对使用开源代码开发自主产品的企业十分瞧不起:“没有核心技术,使用开源代码套壳”。实际上就像没必要重复发明轮子一样,开源代码可以大大节约研发成本,加快信息产品研发的速度,开源生态对信息化的加速进步是居功至伟的。如果一家企业利用开源代码,结合自己的创新技术,开发了自己的基础软硬件产品,那么其无论在技术上还是在商业上都是采用了正确的方法,因为再去重复开源软件曾经做过的事情,效率就太低了。

不过任何事物都存在双面性,开源生态的安全性一直也是受到广泛诟病的,特别是这些年每隔两三年,开源软件就会爆出一两个大瓜来,最近的LOG4J2就是一个十分典型的例子。

如果假想一下,2018年的CPU熔断和幽灵漏洞以及最近的LOG4J2的漏洞,都是某些别有用心的组织埋下的,那么这几年中,这些组织利用这些漏洞,可能已经神不知鬼不觉的干了不少坏事了。如果这些是某些政府支持的组织干的,那就更恐怖了。

去年年初开源社区发生了一件十分重要的事件,可能大家都已经淡忘了。不过因为这件事当时给我的触动很大,4月份的时候我还就此写过一篇文章,所以在最近经常听到网络安全方面的事情的时候,我又想起了这件事。

去年3月份,Linux内核稳定分支的维护者Greg Kroah-Hartman 决定禁止美国明尼苏达大学向主线 Linux 内核提交补丁,因为他们故意提交有安全影响的可疑代码。事实上,在2021年2月,该大学的Qiushi Wu发表了一篇论文《On the Feasibility of Stealthily introducing Vulnerabilities on Open-Source software via Hypocrite Commits》。这篇论文的主要内容就是证明按照某种方法向开源社区提交危险代码,开源社区是无法发现的。我在某些平台上看到这个事件后,就下载了论文,认认真真的读了一遍(有兴趣的朋友可以到https://github.com/QiushiWu/QiushiWu.github.io/blob/main/papers/OpenSourceInsecurity.pdf 去下载阅读)。

这篇论文中介绍了他们团队利用自己掌握的理论向Linux开源社区提交了数个利用UAF(Use After Free)漏洞攻击操作系统,导致Linux崩溃的安全漏洞。

其实现原理比较简单,比如下面有一段修复refcount bug的Linux内核代码,实际上就引发了CVE-2019-12819的Linux系统漏洞:

1 /*Introducing: CVE-2019-12819*/
2 int __mdiobus_register(...) {
3 ...
4 err = device_register(&bus->dev);
5 if (err) {
6   pr_err("mii_bus %s failed to registern",7 bus->id);
8   put_device(&bus->dev);
9   return -EINVAL;
10  }
11 }

上述代码似乎是安全和正确的,当注册设备的时候,如果失败则通过put_device去做善后处理,减少refcount的值,并且当refcount为0的时候释放设备。而在一个更广泛的语境中,put_device中并未再次对指针进行检查,把指针检查交给了调用这段代码的模块,从而为一个UAF错误创造了条件。实际上这个可以引发UAF问题并导致拒绝服务漏洞的代码存在了5年之久才被发现。

从这篇论文中我们可以看到,开源社区的后门或者漏洞是十分难以发现的。虽然Linux社区等也担心后门或者BUG出现在某些补丁包中,并据此设定只接受100行以内的逻辑十分清晰的补丁包。这个规定的目的就是让核心开发者能够很容易的发现这些外部代码中存在的问题。

这个规定似乎能够完美的解决我们所担心的外部代码安全性问题。而事实上,这个工作流程并不完美。据统计,核心代码开发者贡献了48%的Linux代码,33%的Linux BUG和他们的代码有关,其他的BUG都是那些不足100行的代码带来的。这个数据说明什么呢?就是这种代码审核制度的效率并不高。

根据Qiushi Wu的论文,可以通过一个十分简单的方法向某个开源软件中引入恶意代码。其主要原因是开源软件十分复杂,以Linux为例,它拥有3万多个模块,有2万多代码贡献者为这些模块贡献了代码,因此维护如此庞大的软件代码十分复杂。想要向开源软件注入而已代码十分容易。其工作流程如下图:图片

针对开源代码进行分析,发现其中某个不是十分重要的BUG,然后提交一个看似无害的补丁,并在这个补丁中引入可能触发更大问题的代码,不过这段代码只有在特定的条件触发下才会起坏作用,开源社区的测试都无法触发这个潜在的漏洞;然后再利用另外的渠道提交一个可以满足触发条件的代码。这二者只有组合起来才会触发那个漏洞。这些代码很容易瞒过开源社区的审核。

实际上,开源社区在代码管理上十分困难,他们既要接受大量的代码贡献者的代码,从而确保开源社区的高速发展,同时又要防范恶意代码贡献者,从本质上说,开源社区根本无法防范恶意贡献者利用规则在代码中留下特洛伊木马。虽然Qiushi Wu在论文的最后也提出了一个改善开源社区代码管理,从而降低恶意代码提交风险的方法,不过这个方法并不彻底,对于有巨大财力支持的某些别有用心的组织来说,想在开源代码中完全避免恶意代码是极其困难的。

看到这里,可能有朋友要说,这篇文章是否定开源技术,劝大家原理开源代码的,其实不然,开源代码存在风险并不意味着我们要远离开源代码。

事实上,这些年里,开源代码因为发展迅速,功能强大,已经将大量商用软件中的相类似模块替代了。比如著名的OpenSSL,目前几乎所有的商用操作系统和开源操作系统中都把OpenSSL作为标准模块,替代了以前的相关模块。不过IBM/HP这样的企业在引入开源代码的时候,绝对不是简单的使用,而是对这些代码进行了十分严格的分析和优化。

数年前,前面提到的OpenSSL爆发著名的SSL-CCS安全漏洞的时候,我的一个客户的HP-UX操作系统被安全扫描软件扫描出存在OpenSSL-CCS漏洞,于是我向HP申请修复的补丁包。最后HP给我的回复是,虽然目前HP-UX中使用的OpenSSL版本虽然属于存在风险的版本,不过HP-UX中早已对相关的代码进行了加固,HP公司已经确认HP-UX中的OpenSSL不存此安全漏洞。

如果我们使用开源代码研发国产产品的厂家也能像这些国外友商一样,真正把研发经费投入在这些关键安全领域,我想开源代码的安全性问题会得到极大的改善。

基于上面的分析,我的观点是:从一方面来说,我们必须充分利用开源代码,不干重复发明轮子的蠢事,从而加速我国信息化的发展;而另外一方面,针对国家关键的安全领域的软件,最好还是逐渐和开源代码脱钩,转向生态兼容的完全自主代码。

我接触和使用国产操作系统差不多十年了,从基于Linux 2.6.X内核现在发展到了4.x内核。不过我们的操作系统厂商的Linux内核依然没有脱离开源社区的代码,甚至有些厂商依然在使用CentOS的开源代码。这对于具有一定安全要求的应用环境来说会带来巨大的安全隐患。

我曾经使用过一个安全内网使用的国产安全操作系统,其安全主要还是依靠出厂时一次性安装软件,不允许随便安装第三方软件(可以安装经过专用工具签名的第三方软件,不过这种签名工具对安全有何控制能力,十分可疑),不允许删除任何操作系统自带的系统软件(比如OS自带的Mysql,PostgreSQL数据库),也不允许随便升级系统自带的系统软件。

这种安全限制,除了让使用者使用起来更不方便之外(甚至因为软件无法升级而无法及时消除安全隐患),我估计并不会给我们的系统带来我们想要的安全。

当时因为LINUX 4.1内核的系统中带的PG数据库居然是9.x的,不满足我们的系统需求,于是我们只好把一个更高版本的PostgreSQL改了一个名字(改为PGSQL),通过工具签名上传后,用这个所谓的PGSQL替代了原有的PostgreSQL 9.x,完成了我们的软件的安装部署。

我想这样的安全操作系统,其自身能提供的安全保障十分令人怀疑,这个环境中的安全保障主要来自于网络边界上的物理隔离,而不能为我们的系统提供真正的安全,并不是我们在未来安全攻防中所需要的安全产品。

在这个全球一体化受到严重破坏的时代,近些年来对抗的存在是必然的,这决定了对于开源世界,我们的态度是极端分裂的。全球信息化的趋势让我们必须热烈拥抱开源软件,否则我们会在重新发明轮子的时候被世界先进水平越拉越远。但是信息安全的要求又让我们时时警惕不要让我们的信息安全被开源软件中的那些血盆大口所吞噬。

这需要我们的企业在信息系统设计的时候更为谨慎,确保各种安全级别的信息能够存储在不同安全级别保障的环境中。同时加强边界安全平台的建设,在网络边界构筑起足够强大的安全防护体系。而对于我们的国产基础软件厂家来说,也提出了更高的要求,我们不能简单的引入开源代码,更要加大研发投入,在关键性的代码上,实现自主代码替代,从而将开源软件风险降到最低。

在安全级别较高的系统中,我们不能通过简单的限制来提高所谓的安全,而是要让这些环境中使用的操作系统、中间件、数据库等核心基础软件的核心代码逐步脱离开源社区的代码,实现生态兼容下的真正自主化。

发表评论

登录后才能评论
网站客服
网站客服
申请收录 侵权处理
分享本页
返回顶部