在软件开发的过程中,为了提升开发效率、软件质量和稳定性,并降低开发成本,使用开源组件是开发人员的不二选择(实际上,所有软件开发技术的演进都是为了能够更短时间、更低成本地构建软件)。这里的开源组件指的是以开源许可证发布的软件组件、库、框架和工具等,组件的源代码是公开的,而根据不同的许可协议,版权所有者可以授予用户使用、研究、更改和分发软件及其源代码的权力。软件开发人员可以根据所开发程序的不同,选择提供各种功能的开源组件,如Java的SpringBoot框架、Fastjson库、Log4j库,Python中的NumPy库、TensorFlow库,Javascript中的jQuery库等。
对比闭源组件,由于开源组件的源代码公开,使用者能更加容易发现其中存在的漏洞,部分时候漏洞发现者还会提供修复的手段以加快修复进程。然而,并非所有人发现漏洞都会进行通报,对于攻击者而言,公开的源代码使得发现可利用的漏洞更为简单,他们可能并不会将其上报给开源组件的维护者,而是对使用该开源组件的应用进行攻击。另外,由于使用开源组件的程序开发人员大多数对开源组件的源代码并不熟悉,对其的认知仅停留在函数和功能的使用上,对安全性、合法性并无了解,所以这也造成引入开源组件的同时引入了开源组件自身的漏洞,扩大了软件的攻击面。
Black Duck Audit Services团队2023年分析了1703个代码库,并在其年度审计报告中指出,其中96%包含开源组件,其总代码中有76%是开源代码,84%的代码库包含至少一个已知的开源漏洞,48%的代码库包含高危风险漏洞。
根据新思科技(synopsys)2023年的报告《开源安全与风险分析报告》显示:
1703个代码库中,54%的代码库有开源协议冲突,31%的代码库包含没有协议或自定义协议的开源代码,89%的代码库包含超过4年以上未更新的开源代码,91%的代码库包含过去2年未更新的组件,84%的代码库包含至少一个开源漏洞,5%的代码库包含有漏洞的Log4J版本,11%的Java代码库包含有漏洞的Log4J版本。
Gartner预测:
到2025年,全球将有45%的组织的软件供应链遭受攻击,比2021年增加三倍。
根据Veracode 2022年的报告《软件安全状态》显示:
97%的Java应用是由开源组件库构成,77%的第三方组件库漏洞在三个月后依然未被修复。
从上述的报告和预测中可以预见,未来软件安全中开源组件的安全问题会成为软件安全的聚焦点。引入第三方组件导致的安全问题可能造成严重的后果可以参考下面的三个案例:
1992年,Borland InterBase 数据库软件出现隐藏后门事件,该后门在软件中潜藏了8年之久,是由该软件的开发人员写入的,允许未经授权的用户通过特定的用户名和密码访问数据库,并执行一些特权操作,如修改、删除数据。开发人员的用意可能并非主观恶意,但是该后门如若被攻击者提前知晓,便会造成全球范围内的严重后果。
2014年,Heartbleed(心脏出血)漏洞爆出,造成了加拿大税务局泄露了近900人的社会安全号码(Social Security Number,它被用作个人信用记录、就业背景检查以及金融交易中的身份验证等)以及各大网站的用户敏感信息泄露。
2021年,核弹级Log4j漏洞爆出,该漏洞会让攻击者在受害者主机上执行代码,可造成服务器权限被获取,信息泄露等危害。
这些组件正是由于被广泛使用来提升开发效率,导致一旦爆出漏洞,其对于应用程序的危害最终会波及到世界各地的企业集行业,并最终损害到用户利益。
开源组件产生漏洞的原因有很多,根据我们对于最常出现漏洞的Top 20开源组件中最多遇到的漏洞分析,根本的原因如下:
-
开发人员编写的代码存在漏洞;
-
组件引入了其他存在漏洞的组件;
-
攻击者/受信任的开发人员向该组件源码提交了恶意代码;
-
开源组件所使用的配置文件存在默认安全问题,且用户使用时没有修改。
在开发软件过程中引入的开源组件漏洞不仅会影响到软件的安全性,也会影响到软件的简洁、健壮和稳定,这些技术债务会进一步影响软件的迭代、交付和运营。
此外,开源组件还存在许可协议的问题,许可协议意味着并非所有的开源组件都可以按照使用者的意愿随意使用,部分采用严格的许可协议的开源组件会要求使用该组件的应用程序也必须公开其源码,并限制其商业模式,或是受到开源社区的约束。如使用以GPL3.0协议开源的组件,自身也必须遵循该协议,需要将源代码保持开源和免费。
如果违反使用组件的开源协议可能会造成法律风险和后果:
2017年10月,深圳市中级人民法院某判决显示,使用GPL3.0协议开源组件而未遵循其约定公开源代码的某公司罚款50万元。
2021年10月,软件自由保护协会(Software Freedom Conservancy,SFC)对智能电视制造商Vizio提起了诉讼,指控其未遵守GNU通用公共许可证(GNU General Public License,GPL)和GNU Lesser General Public License Version 2.1(LGPL v2.1)的规定。SFC声称Vizio在其智能电视中使用了包含Linux内核和其他代码修改的SmartCast代码,并未按照GPL许可证的要求发布修改后的源代码或提供书面要求提供源代码的声明。诉讼要求Vizio提供完整的源代码,并要求法院裁定GPLv2和LGPLv2.1要求Vizio提供源代码或书面声明的条款。
2009年12月,软件自由保护协会(Software Freedom Conservancy,SFC)对西数(Western Digital)提起诉讼,指控将 BusyBox集成到他们自己的产品中违反了 GPL 许可。2018年7月27日,经过裁决,法院禁止西数销售配备BusyBox的产品,同时,要求西数支付90,000美元的损害赔偿金和法律费用(约合47,000美元)。
Black Duck Audit Services团队的数据表明,在2022年审计的代码库中,54%的代码库包含了许可协议冲突,影响最大的行业是物联网,协议冲突比例高达78%。对比2021年,总体的冲突数量在减少,原因可能与经济下行和对供应链安全的焦虑相关。
自20世纪90年代以来,随着开源软件(Open Source Software, OSS)的普及,与OSS相关的风险也被发现和重视,包括:
-
OSS版本变动引入的风险;
-
组件漏洞的风险;
-
许可协议带来的法律风险;
-
现有代码以及OSS的兼容性风险;
-
OSS文档质量差和过时的风险。
在1998年发现该问题后,人们最初是使用电子表格和文档来跟踪开发人员使用的所有开源组件,这是一种SCA(Software Composition Analysis)技术,用于管理开源组件的使用。但是人工的统计效率低下,且没有一个较好的管理标准,于是2002年,第一个手动开源扫描工具诞生,但是这种技术早期仍然误报率高,需要人工干预,不符合敏捷开发环境的需求。到2011年,SCA技术得到进展,能够实时自动检测漏洞和许可问题,这使得软件开发人员能在开发周期的早期就进行开源组件管理。同时,SCA工具也在发展,如今已经能与存储库、构建工具、包管理、CI/CD等软件开发工具集成。
除此以外,美国NIST(National Telecommunications and Information Administration,国家电信和信息管理局)提出了SBOM(Software Bill of Materials)概念,并在2021年7月发布了SBOM所包含的最小必需元素。
-
数据字段:存储供应商、组件名、组件版本、组件依赖关系、时间戳、其他唯一标识符、SBOM数据作者。
-
自动化支持:支持自动化,SBOM可通过工具自动生成,并具备机器可读性,以允许在整个软件生态系统中扩展。用于生成和使用SBOM的数据格式包括SPDX,CycloneDX和SWID标签。
-
实践和流程:定义SBOM的请求、生成、使用操作,包括:频率、深度、已知未知、分发和交付、访问控制、错误调整。
SCA工具的首要功能是进行组件检测,它会分析项目的源代码、配置文件和构建文件,确定项目中使用的外部依赖库版本和组件。这些依赖可以通过各类语言的管理组件以及其版本的包管理文件来进行依赖组件的自动化识别,如package.json,pom.xml,go.mod,.gradle等。这些文件记录了软件开发过程中使用到的第三方组件,以及第三方组件使用到的一些开源组件。
此外还可通过代码片段、组件哈希值来识别组件,代码匹配主要通过文本比较、代码指纹、代码克隆检测、语义分析、语义分析等方式进行匹配。这几种技术各有优劣:
-
文本比较算法可能无法捕捉到代码结构和语义上的相似性;
-
语法分析可能会导致相似代码匹配上同一个组件导致判断不准确;
-
语义分析建立准确的模型较难,并且在大型代码库中进行全面的语义分析可能耗时较久;
-
代码指纹的生成算法同样会影响匹配的准确性和全面性,并需要规模庞大的指纹库。
随后,SCA工具会解析项目的依赖关系,包括依赖库之间的版本关系和传递依赖关系,传递依赖关系指的是所引入的开源组件自身也引入了其他组件。
最后,SCA工具将所得的组件依赖关系与已知的组件漏洞库进行比对,检查项目所使用的开源组件是否存在已知漏洞,如若存在则进行漏洞报告。另外,SCA工具还会对组件的许可协议信息进行分析和解释,它会确定哪些许可协议是兼容的,哪些是不兼容或有商业使用的潜在风险的,并给出相应的建议和措施。当前的SCA工具往往也能够生成SBOM,帮助开发团队更好地了解和管理软件项目中的组件及其相关许可风险,从而确保合规性和安全性。
SCA工具属于一种静态分析工具,可以帮助开发团队识别和追踪应用程序中的开源组件信息和漏洞信息,以便及时发现和解决与这些组件相关的潜在安全漏洞和许可证合规性问题。但是其使用中也会存在一些问题:
-
检测的组件可能会出现误报,或者版本不对的情况,这源于包管理文件的识别错误或是代码匹配的匹配错误。
-
漏洞库更新的滞后性以及其解决方案并不符合实际场景,大多数企业并没有精力维护开源组件漏洞库,而SCA漏洞数据通常源于一些公开漏洞库,如CISA (US-CERT)、NIST (NVD)、MITRE (CVE)。不对外联网的情况下,会造成对于新漏洞更新不及时以及解决方法不存在的情况。
-
对于冷门语言的支持性不足,部分语言SCA工具不支持开源组件的识别。
-
扫描的安全漏洞实际可能并不存在,如所引入的组件被包括在了包管理相关文件中,但实际上项目并没有使用组件的漏洞函数,这时的漏洞实际是误报。
-
工具虽然提供漏洞的检测和报告,但最终的漏洞修复依然需要人工执行。修复过程可能涉及代码修改、组件配置、升级(依赖)组件版本等操作,其中不同的修复方式对开发项目会带来不同的修复成本(如架构重构),因此会让开发团队对于漏洞修复望而却步。
为了解决以上的问题,提前规避和降低软件开发过程中的风险,需要结合其他的方法。如在开发过程中引入第三方组件时,提前过滤和筛选较为活跃的开源组件项目,具体可以从项目上一次合并的提交时间、提交频率、维护团队人数、社区活跃度多维度评估该组件的活跃性,活跃的项目被攻击者关注的同时,也会被安全人员关注,因此其修复漏洞的效率也会因此变快。
例如下图中的Gitee指数:
并且经常对漏洞库进行更新,对自身所使用组件的漏洞进行订阅,对出现组件误报的情况进行人工验证,同时搭配诸如WAF、RASP等安全防护工具,配置其防御规则,对尚未提供更新版本的组件漏洞利用进行拦截。对于一些行业,如航空航天,汽车,交通和物流等行业,由于其特殊的运行环境和系统结构,可以通过其他措施来降低漏洞的风险,而不是仅仅依靠更新组件到未出现漏洞的办法。这些措施可能是网络隔离,访问控制和监测等操作。当然这并非是说在封闭的系统中,漏洞修复不重要,因为如果封闭环境中漏洞普遍存在,一旦攻击者进入内网,内网可能很快瘫痪。
此外,SCA工具也应当集成到开发人员工具中,如将其作为Atlassian Bamboo,AWS CodeBuild 等CI/CD工具管道中的自动化任务,以便将识别和修复漏洞成为软件开发和构建过程中的第一部分活动。这样不仅可以让开发人员适应代码安全,还可以防止后续检测出安全漏洞时做代码重写。
综上,虽然SCA工具能帮助企业管理所开发应用的依赖关系,检测所使用组件的安全问题以及合规性问题,但真正的安全防护以及漏洞治理还是需要多方面的结合来实现。
作者: hu1y40
2024年3月5日
洞源实验室