“开源软件具有开放、共享、自由等特性,在软件开发中扮演着越来越重要的角色,也是软件供应链的重要组成部分。据Gartner调查显示,99%的组织在其IT系统中使用了开源软件。而来自Sonatype公司的一项调查则显示,在参与调查的3000家企业中,每年每家企业平均下载5000个开源软件。
然而,开源软件中存在大量的安全隐患,企业在享受开源软件带来的便利的同时,也在承担着巨大的安全风险。近年来,开源软件频繁爆出高危漏洞,例如Strusts2、Open SSL等。这些组件很多都应用于信息系统的底层,并且应用范围非常广泛,因此漏洞带来的安全危害非同一般。”
美国首先认识到开源软件安全问题的重要性,早在2006年,美国国土安全部就资助Coverity公司开展“开源软件代码测试计划”,针对大量开源软件进行安全隐患的筛查和加固,截至2017年2月,累计检测各种开源软件7000多个,发现大量安全缺陷。
鉴于上述形势,360代码卫士团队基于自身技术积累和产品能力,在2015年初发起了国内的“开源项目检测计划(www.codesafe.cn)”,这项计划是针对开源软件的一项公益性安全检测计划,旨在让广大开发者关注和了解开源软件安全问题,提高软件安全开发意识和技能。截止2017年初,该计划已检测2228个开源项目,获得了大量的缺陷检测基础数据。
开源项目检测计划数据和实例分析
从2015年初到2017年初两年多时间中,360代码卫士团队从GitHub、Sourceforge等代码托管网站和开源社区中选取了2228个使用比较广泛的开源项目进行检测,涉及的开发语言包括C/C++/C#/Java等。
检测代码总量257,835,574行,发现源代码缺陷2,626,352个,所有检测项目的总体平均缺陷密度为10.19个/千行 (KLOC)。
针对安全缺陷检测结果,360代码卫士团队从多个视角进行了统计分析,并归纳总结出开源软件的安全现状。本次分析主要从以下3个维度对检测结果进行说明:
-
依据缺陷危害程度、可利用性、受关注度等因素,在所有缺陷类型中,选择10大重要缺陷进行数据统计,同时统计所有开源项目中存在这些缺陷的比例,以展示开源项目中重要缺陷的分布情况。
-
参考代码托管网站和开源社区的项目Fork值、下载量等指标,选取20个流行项目的检测结果进行深度分析,分析从缺陷总数、10大重要缺陷总数以及缺陷密度三个角度进行,以说明流行开源项目的源代码安全状况。
-
综合统计2228个被分析的开源项目,排列出缺陷总数最高的10个项目,以说明安全风险相对较高的开源项目的情况。
1、10大重要缺陷统计
在所有检出缺陷种类中,依据缺陷类型的危害程度、受关注度等因素,选择10类重要缺陷进行检测结果分析,图1是10大重要缺陷统计列表(按检出数量多少排序),图2是10大重要缺陷在2228个项目中出现的比率。
图1 10大重要缺陷统计列表
统计结果显示,在选取的10大重要缺陷中,检出数量最多的是系统信息泄露,达到18万余个。而受到开发人员普遍关注的缺陷,如SQL注入、跨站脚本也分别检出4096和9614个,这两类缺陷是web攻击中最常见的两类漏洞,可见它们依然是web应用中修复的重点。
图2 10大重要缺陷检出比例
在本次检测的2228个项目中,有高达82.99%的开源项目存在10大重要漏洞,说明这10类缺陷普遍存在,应当作为软件安全保障的重点考虑问题。
2、20个流行项目检测结果
参考代码托管网站和开源社区的项目Fork值、下载量等指标,团队选取了20个最受欢迎项目的检测结果进行了统计分析,图3是20个流行项目缺陷数量统计表,图4是20个流行项目出现10大重要缺陷数量统计表,图5是20个流行项目缺陷密度统计。
图3 20个流行项目缺陷总数
20个流行项目中,Guava项目检出的安全缺陷数量最多,Guava是Google 的一个开源项目,包含许多 Google 核心的 Java 常用库。
图4 20个流行项目中10大重要缺陷的总数
20个流行项目中,netty项目检出10大重要缺陷的总数最多,达到384个,即该项目源代码中存在高风险缺陷的数量较多。
图5 20个流行项目缺陷密度统计
缺陷密度可以从一定程度上反应项目的安全性。在上述20个流行项目中,okhttp的缺陷密度最大,为45.24个/千行;opencv的缺陷密度最小,为0.91个/千行。
3、缺陷数量TOP 10项目
在检测的2228个开源项目中,仅从缺陷数量角度,对所有项目检出的缺陷数量进行排列,其中缺陷总数最多的10个项目如图6所示。OpenGamma项目成为2228个项目中检出缺陷数量最多的项目。
图6 缺陷数量TOP 10项目
4、漏洞验证实例分析
通过开源项目检测计划,360代码卫士团队自主发现开源软件漏洞31个,并已获得29个CVE漏洞索引编号(CVE-2015-8665、CVE-2015-1923、CVE-2016-1924、CVE-2016-2073、CVE-2016-2089、CVE-2016-1867、CVE-2015-8751、CVE-2015-8883、CVE-2015-8884、CVE-2015-8885、CVE-2015-8886、CVE-2015-8887、CVE-2016-6523、CVE-2016-6821、CVE-2016-7149、CVE-2016-7150、CVE-2016-9418、CVE-2016-10037、CVE-2016-10038、CVE-2016-10039、CVE-2017-7984、CVE-2017-11723、CVE-2017-12065、CVE-2017-12066、CVE-2017-11660、CVE-2017-11659、CVE-2017-11164、CVE-2017-9729、CVE-2017-9728)。
本节基于CVE-2015-8883漏洞进行详细的漏洞验证实例分析。该漏洞是一个类型混淆漏洞,存在于一个由C语言开发的开源流媒体解析软件包中,位于核心处理函数HandleInvoke中,调用AMF_Decode函数对body数据进行解码,然后将body数据传给了AMFProp_Decode函数的pBuffer中,在AMFProp_Decode函数中存在一个switch语句,它会根据不同的数据类型标志位对数据进行解码。在我们的poc中,根据p_type调用了AMF_DecodeNumber函数对pbuffer进行了解码。注意数据在随后的使用中实际上是当作一个对象来使用,应当使用AMF_Decode函数进行解码。如图7所示。
图7 数据解码过程
在调用AMF_Decode函数对数据进行解码之后,obj中就存储了解码后的数据。随后在3108行中,调用AMF_GetProp函数从obj中获取索引为3的prop属性数据,紧接着在AMFProp_GetObject函数中将prop中Union数据p_vu以AMFObject对象类型的方式取出,并存储到obj2中。在3109行中,再次调用AMF_GetProp函数从obj2中获取数据。在我们的poc中,obj2中实际上存储的是一个double数据,程序将其当作指针进行使用,可能会导致程序访问非法的内存地址。如图8所示。
图8 非法内存地址访问过程
结论与建议
从开源项目检测计划所得到的数据来看,当前开源软件的安全问题非常严重,代码中的安全缺陷密度较高。而据NVD数据统计,截至2017年2月,全球开源软件相关的已知安全漏洞已超过28000个。
随着软件开发过程中开源软件的使用越来越多,开源软件实际上已经成为软件开发的核心基础设施,开源软件的安全问题应该上升到基础设施安全的高度来对待,应该得到更多的、更广泛的重视。
而据我们目前观察到的情况,当前绝大多数企业在软件开发过程中,对开源软件的使用非常随意,管理者常常不清楚自己的团队在开发过程中使用了哪些开源软件,甚至程序员自己都无法列出完整的开源软件使用列表。这给信息系统安全风险的管控带来了极大的挑战,系统的运维者不清楚自己正在运行的软件系统中是否包含了开源软件,包含了哪些开源软件,这些开源软件中是否存在安全漏洞!
在此我们呼吁和建议,开发者在软件开发过程中使用开源软件时,不应仅仅关注开源软件的功能,还应把安全作为重要因素纳入考量,尽可能避免由于不当的使用开源软件而引入严重的安全隐患。开发者可以通过“360开源项目检测计划”网站(www.codesafe.cn)了解自己关注的开源软件的安全缺陷检测细节,及时防范安全风险。
(本文作者:360开源项目检测计划负责人 吴迪 | 文章刊载于《互联网安全》第22期,点击阅读原文可查看杂志电子版。)