你是否知道工程师随便编写的一个返回"Hello World"这么简单的微服务,后面居然依赖着上百个软件包、5万多行代码?你又是否知道这些软件包在开源世界的来源、它们能带来什么样的安全风暴?
现如今引用开源项目成为再习以为常的事,但你知道如果用的这个开源代码包是一个遭黑客污染过植入了后门的有毒组件,会有什么影响吗?今天想聊聊软件供应链攻击。
各行各业都有供应链,就像一家车厂,它生产整车,不可能从轮胎、车窗玻璃、车门把手做起。正如物理世界的任何产业都有自己的产业链、供应链一样,在虚拟世界的软件业也一样,任何终极软件产品,都用到很多的虚拟“零部件” - 以代码库形态存在的组件、框架、工具,而且这些“零部件”本身也高度依赖其他“零部件”。
实际上,随便一个软件,按绝对代码行数来算,一个不小心有一半是第三方的,例如在一些微服务里,自己的代码只占10%,也一点都不奇怪。
Hello,World 隐藏的秘密
每一个软件工程师在学习一门新技术的时候,都会从最简单的“Hello,World”程序开始。可是世界上确实没有免费午餐 - 表面越简单的东西背后的代价可能也越大。例如,你想用JavaScript Node.js开发一个只能对网络请求返回“Hello,World”回复的微服务,你决定采用一个最轻量简约的微服务框架ExpressJS - 一动手的瞬间,你的开发工具npm就给你从上游拉取100 软件包 - 54,000行代码拿去,不谢。如果你想再玩点高级功能,例如添加一个MVC框架(例如Locomotive),你的这个“微”服务实际代码量马上升至220,000行 - 不好意思,起步价,哪怕你只写一行代码。
每年各语言新增软件包数量,其中npm生态2019年新增超过30万个。上图缺乏新兴语言如Golang、Rust等的数据,但这些语言生态中的“零配件”数量的快速增长,对于开发工程师来说,都是可直接感知的。相比之下,Java、Ruby的组件生态增长率较低,但很大程度因为它们已经增长了近二十年,基数已经极其庞大。
软件供应链远比想象的无序凌乱
一套软件的供应链,如果把它画出来,很有可能是这样的:
可以说,今天的绝大部分开发者,根本搞不清楚自己的软件供应链里都有谁,因为他们所用到的很多技术组件都是他人提供的,这些“上游”组件本身又用了什么其他组件、工具,开发者们往往不知道也不关注。可以说,我们在生产一个软件产品的时候,很可能“非自愿”的集成了大量“上游”、“上游的上游”、“上游的上游”的半成品。
对于企业来说,当前软件供应链起码面临四类风险。
1、软件质量风险
企业软件表面上由IT或者外包商开发,可是实质上背后是成千上万的第三方开源代码,企业的QA工程质量管理方法和流程,对于第三方完全失控无效。
2、长期支持风险
企业软件所间接依赖的一些第三方开源零部件,并没有商业体在背后提供质量承诺和长期支持。开源项目因创始人退出或者社区活跃度低而不再维护、半途而废的,不在小数。产生维护支持需求时,企业自己不得不安排人手去处理该部分代码,先不说有没有这个意愿,企业自己的IT工程师是否有这个能力也难说。
3、知识产权风险
开源软件的知识产权机制,反映在著佐权(Copyleft)和许可证(Permissive)。后者约束了你的软件的分发传播需要满足的条件,前者则往往更进一步要求你用开源组件开发的软件本身的源代码必须沿用同样的开源条款,导致你的软件知识产权不得不公开。国内软件企业在使用开源、贡献开源的过程中规则意识普遍薄弱,存在错误混用不兼容的许可证,违反许可证规定二次发布等问题,带来更为复杂的知识产权问题和法律合规风险。
4、信息安全风险
在开发人员写第一行代码前,一个系统可能就注定继承了一堆“安全债务” - 部分取决于这个系统的设计者、开发者选择采用什么第三方组件,部分取决于这些第三方组件的开发者又选择依赖于什么别的组件。反正安全风险是传递的,只要有一个零部件有安全漏洞、甚至是在漫长复杂的互联网分发链路上被篡改过注入了恶意代码,你的系统就继承了所有这些风险。
如何化解软件供应链中的风险
虚拟世界的“恶意”代码,也只能用虚拟的“牢笼”去“关住”它。安全沙箱(Security Sandbox),就是这么一种数字牢笼,它的形态和技术实现方式有很多种,本质上它是一种安全隔离机制,通过构建一个封闭的软件环境,隔离了它所在的“宿主”的资源包括内存、文件系统、网络等等的访问权限。运行在这个封闭环境中的进程,其代码不受信任,进程不能因为其自身的稳定性导致沙箱的崩溃从而影响宿主系统,进程也无法突破沙箱的安全管控以读写宿主系统的资源。
沙箱类技术以各种形态出现:在BSD等操作系统里就提供直接叫做“Jail”的虚拟化隔离;在JVM里为了支持Java Applet这里网络加载的代码的运行,实现了sandbox机制;浏览器里的HTML渲染引擎,一定程度上也可以视为一种在用户态的基于安全能力模型(Capability-based)的沙箱技术。