从开源组件安全现状浅谈开源组件安全运营

0x00 前言

最近几个月时间完全变成了一个彻底的RD,当然不能说这件事儿是坏事,起码有更多的机会能够靠近业务和了解业务,从干安全的第一天起就被各位领导灌输运营很重要,运营很重要,自打从2018年加入美团信息安全团队后就一直在研究威胁情报如何和业务相关联体现出重要性,很不幸的是突破来得太晚了,目前也就发现了几个场景可以关联起来。限于标题的原因,我们今天只讨论一下开源软件安全相关的东西。

说明:以下的文章仅代表个人观点,不代表其他的观点,如果有不认同的地方,欢迎加本人的微信进行友善的讨论。


0x01 从一份报告看开源现状

广义上的开源软件实际上就是给予各种协议公布源代码让所有人使用的软件,源代码只要遵守对应的协议就可以使用,我们在这里说的开源软件实际上是Open-Source Software的缩写,考虑到这个范围实际上还是很大,本文只讨论面向以下场景的安全问题和运营策略。我们在这里定义一下OSS的范围,包括但不限于以下的范围:

  • 服务器端软件仓库及对应的管理生态:如Maven、NuGet、NPM、PyPi等
  • 客户端软件仓库及管理生态:如CocoaPods
  • 操作系统软件仓库及管理生态:如YUM、APT、Brew等
  • 开放代码仓库及管理生态:如GitHub、Gitee等
  • 容器仓库及管理生态:docker pull下来的Image

在这里我就直接引用了SNYK.IO的关于2020年组件安全的一份报告中的数据了,从各个源的情况来看,NPM源是当之无愧的最活跃源,2015-2019年每年提交到NPM的package数量最少也就将近20w的数量,于此同时,提交到RubyGems的package数量从2015年的10w附近跌到了几千个package一年,没落的有点快,数据如下图。

上面的数据说明了每年新引入的组件数量非常多,如果说漏洞呢,从2014年开始到2019年的各个源的漏洞变化情况是这样的

NPM不仅新引入组件的数量是第一,漏洞引入的恶数量在2014-2018年增长的趋势也是最快的一个,而Maven呢,实际上一直很多,这个和Java用途广泛而且都是企业级开发有关系(企业开发者相比个人开发者而言,可能更重视开发安全),从上面这些数据来看,可能从2017年开始,组件安全开始受到了重视,所以每年发现的漏洞也就越来越多。

按照漏洞的危害程度来分析,2017年开始高危漏洞基本上在1000附近浮动,这里SNYK对于高危漏洞的定义是依照CVSS分数来划分的(后面我们会说这个里面实际上是有坑的),可见中高危漏洞是一年比一年多。我们如果按照漏洞类型分类去划分的话,看到的就是下面这个样子。

XSS一骑绝尘,这个原因大家都清楚(估计有不少人的人生首洞都是XSS,甚至是Self-XSS),排第二的是命令执行类的漏洞(妥妥的高危漏洞)。在这里面又个非常好玩的事情,排第五的恶意包从2017年开始发现一直到现在占据到了第六的位置,可见供应链攻击在这三年内发展的速度有多猛。如果说我们单独看2019年top10漏洞的分类,数据是下面这样的。

对你没看错,恶意包已经排到了第二了,仅次于XSS,比信息泄露和拒绝服务的总和还要多,更别说命令执行类(ACE和RCE)的漏洞,所以此时此刻讨论供应链攻击的防治可以说必要性非常高了。

在讨论漏洞影响面分析的时候,除了漏洞的危害,资产影响数量也是一个很重要的衡量指标。把这个数据对应到组件安全中,应该是所有项目对于问题组件的引用数量。如果按照影响范围和漏洞类型进行分类的话,数据就变成了下面这样。

这么看的话,原型污染变成了第一,反序列化紧随其后。原型污染能当第一的原因有很多,主要是因为每年NPM大量引入组件,同时NPM每年新增的漏洞有不少,再加上用NPM构建的项目基数又很大,所以原型污染变成第一也就理所应当了。至于反序列化嘛,你们懂得,序列化和反序列化是很常见的操作,再加上这两年大家都在盯着weblogic等组件搞,所以反序列化漏洞数量变多也很合乎情理。这个时候我们发现恶意包突然不见了,其实下图很好的说明了原因。

如果按照影响项目的数量来看,恶意包的被引用次数实际上是最少的,而且极其容易被发现,反序列化漏洞和原型污染漏洞占据份额的top2很大一部分原因也是有很大的基数在做支撑,说人话就是用的人多了。

以上数据是从漏洞类型和资产基数的角度上来看开源组件的安全问题,如果我们放到每个源来看,情况变得有意思了起来。首先我们先从低危漏洞看起,最具代表性的是XSS漏洞,每个源历年的XSS漏洞数量如下图所示。

这个时候PHP果然就变成了成绩“最好的”的语言,数量逐年看涨而且2019年突破100大关,这里NuGet的数据比较抢眼,但是我们不能下NuGet的安全管理做得好,原因下面说。当然低危漏洞数量多少其实说明不了什么,我们下面来看下高危漏洞。

低危漏洞管控最好的NuGet一跃而成了高危漏洞的top1,当然这个可能是微软的SDL做的很好,能够发现高危漏洞。

以上我们说的都是对于各个源的安全情况,下面我们来说一下docker image的安全情况,从各种类型的docker image来看,漏洞数量如下图所示。

突然为写前端和nodejs技术栈的老板们捏了一把汗,除了组件之外,docker的问题也蛮严重的。既然说到了docker,那么顺便看一下kubernetes的包管理系统helm的情况。

可能是语言特性的问题,溢出漏洞变成了top1,其次是访问限制绕过。

通过上面的数据,我们大概能从这份报告中了解到以下几点情况。

  1. 随着新引入组件和基于这些组件的开源项目越来越多,漏洞的数量也是越来越多的。
  2. NPM漏洞多的原因是因为每年增加的包的数量最多、使用NPM做包管理的项目最多等多种原因导致的
  3. 供应链攻击(恶意包)的占比在近三年越来越大,2019年有接近XSS的趋势。
  4. 漏洞危害很大一定程度上取决于漏洞本身的危害和组件引入的数量,二者是相乘的关系而不是相加的关系。

0x02 风险背后的机遇——开源组件漏洞运营

前面说了这么多的风险,确实在开源组件领域,很多安全产品和安全运营策略都是刚刚起步,有很多不完善的地方,虽然说有很多产品宣称具备全面的解决方案,但是从业务的角度来讲,未来的趋势一定会是让系统在设计的时候就是安全的,也就是所谓的原生安全(native security)。

在开始谈运营策略之前我先提出几个问题,当然这些问题在后面都会有解答。

  • 开源组件安全有没有一个通用的SOP?
  • 是否有必要建立一个独立于CVE数据库之外的组件安全数据库?
  • 所有的高危漏洞都需要修复么?
  • 低危漏洞是否需要修复?
  • 为什么仅依赖CVSS分数判断漏洞危害是不靠谱的?

以上的问题实际上在实际的操作过程中,绝大多数都有明确的答案,但是鉴于不同公司的业务情况不同,实施的情况也是千差万别。所以我们先来梳理一下在业务场景下,开源软件会引入哪些风险。

首当其冲的是漏洞引入,当然危害最大的是引入在野漏洞和高危漏洞,引入漏洞会导致系统出现风险,能够被攻击者轻易利用,造成系统被攻击者控制,更严重的可能会变成一次渗透的导火索。

排第二的是恶意包引入,也就是所谓的供应链攻击,供应链攻击引入的风险包括但不限于引入后门、恶意挖矿、勒索等。这种攻击一旦发现基本上是肯定中招了,尤其是在HW期间,可能攻击队会利用这种手段进行大规模抓鸡。这一部分我可以分享一些数据,通过各种渠道,我们累计抓到了1240个供应链攻击的恶意包,其中有将近600个都是来自于NPM,而且危害均是前端挖矿。(以上数据不一定全)

接下来是中低危漏洞组合拳,也就是说攻击者不利用高危漏洞对系统发起攻击,而是利用若干中低危漏洞做组合拳对系统发起攻击,比如说XSS+SSRF进行蠕虫攻击。这种攻击实际上是利用的安全运营团队忽略了对中低危漏洞的修复的实际操作发起攻击的。

第四类实际上也是属于组合拳,但是不是中低危漏洞,而是gadget链式利用漏洞,如jackson的反序列化中间会利用到几个类充当gadget绕过。这种类型一般是绕过安全机制或者缓解机制,对系统进行攻击,考虑到一个成熟稳定的系统内部必然是复杂的,所以这种攻击得手率还是蛮高的。

以上说了漏洞的利用方式,那么问题来了,如何发现这些高危漏洞并作判断。在讨论这一部分之前我先来说点别的。

虽然说通用漏洞和基础组件漏洞都是漏洞,二者的相同点是都会对系统造成预期之外的影响,但是在我看来二者的不同点更多。首先通用漏洞的作者往往不是微软、IBM这种大厂,也不是Apache这种机构,很多情况是小厂和个人开发者,大厂和权威机构与他们相比,代码质量和SDL机制比较健全,并且由于大厂就是大厂,在安全社区和安全公告的多年深耕已经完成了一套科学严谨的SOP,并且这些大厂均具备CNA资质,也就是说这些大厂可以分配CVE编号给符合条件的安全漏洞,所以这些大厂的通用漏洞通过CVE可以覆盖是完全没毛病的,这一定义可以延伸至大厂旗下的开源组件。反观小厂和个人开发者,且不说对于安全开发的意识普遍不高,不具备CNA资质也就意味着这些漏洞很不容易被官方曝光,仅能成为安全圈子内朋友圈茶余饭后的谈资甚至是朋友圈驱动的告警运营。通过对各个源的安全公告和朋友圈的整理,我们累计发现了约30w组件相关的漏洞(聚合维度为源+漏洞),考虑到CVE编号到现在还不到15w,所以还是有很大一部分组件没有CVE编号的漏洞。

如果说编号问题只是能说明漏洞不好标示,那么缺乏CVSS则会让漏洞分析研判的自动化程度变低,由于CVSS分数只是一个分数而已,所以CVSS的分数可能并不会对漏洞评估研判产生效果,但是CVSS的细则(AV:N/PR:L/C:H/I:H/A:H这种东西)则对于漏洞评估工作有帮助,但是很多漏洞连CVE都没有,更何况CVSS,但是好在有些源会给这些漏洞一个CVSS细则,这样可以减少我们自动化评估的难度,但是仍然有一部分工作无法自动化,在这里我们可以使用NLP技术抽取漏洞描述中的描述性词汇,并进行聚类统计和加权统计,最后可以估计出一个CVSS的细则,继续沿用之前自动化评估的细则,则可以完成对这类漏洞的自动化分析(这部分可以通过设置正反向指标来评价算法工作的好坏,诸如自动化处置率和坏样本比例)。由于我们通过NLP技术对公告的语义进行了分析,影响范围也就顺手抽了出来,这样的话自动化分析的问题也就算是基本解决了。(插句题外话,这个算法也运用到了现在TTPs情报生产上)。

如果之前的编号和影响分析的问题都解决了,那么接下来的问题其实更加棘手,如何判断影响面。从抓手来看,代码仓库、CI/CD平台、主机文件都可以是开源组件检测的抓手,但是实际实施上,会有很多客观因素导致数据不准,比如:

  • 主机agent覆盖率和采集精确度
  • 投后/收购资产是否纳入现在的研发体系
  • 是否有不通过发版系统发布的系统
  • 机器学习/OLAP/实时计算/离线计算作业是否也存在包引用的情况
  • 在自己的终端上调试
  • 数据同步周期大概是多久

以上的这些问题会很大程度上影响漏洞运营的质量和精度,可能会造成该修的漏洞没有修了,已经修了的漏洞天天报警,如果有上升机制可能会把这些无效的ticket上升至VP/SVP/CTO。。。后果不堪设想。所以这个时候需要建立一个数据-资产自动化交叉机制,可以以计划任务的方式或者是离线计算的方式来完成数据的加载,需要注意的是,优先级是发版系统构建日志/计算任务构建日志>主机agent文件/进程采集数据>CI/CD数据/白盒>代码仓库。因为组件引用、调用、使用是一个连续的过程,引用不一定调用,调用不一定使用,所以在发版系统采集的构建数据一定是在用的。

如果前三步走的很顺利,接下来就是一个推修的过程了,实际上这一部分和传统漏洞的流程是一致的,所以此处省略,有很多文章说的已经很好了。当然在这里需要通过考察漏洞修复运营质量,定期按照BG/BU进行风险修复排名和晾晒,会让大家重视安全这件事儿,这些指标越来越好,也就能体现出安全工作做得越来越好。


0x03 未来的思考——检测开源组件风险

当然仅仅依赖被动采集情报去驱动风险修复这件事儿,实际上仍有一部分问题解决不了,从上面的数据来看,我们无法对全球所有的安全组件进行安全追踪和分析,所以这个时候如果有一个数据库可以支撑对引用包的检测,是最好不过的。

对于包安全检测而言,实际上和常规的软件检测无差别,主要手段也是白盒审计和灰盒fuzz,同时通过沙箱分析包的行为,这一部分可以看腾讯TSRC的文章security.tencent.com/in,从已知资料来看,他们目前做的是比较靠前的。

对于开源组件安全这一部分,实际上我们在解决问题的时候应该考虑业务的诉求,除了极个别高风险的情况,安全团队思考问题的角度不应该是一刀切的不让用,而是如何让业务更安全的取用开源组件去构建系统,只有当业务理解安全工作的时候,安全的价值才能发挥到最大。

最近很多人咨询之前的群的问题,由于某些原因群被解散了,如果有技术交流需求可以直接添加微信(猎头HR勿扰)。

编辑于 07-28

文章被以下专栏收录