第五章 软件透明度的挑战 在美国国家电信和信息管理局 (NTIA) 软件物料清单 (SBOM) 计划的早期讨论中,设备的 SBOM 主题作为一个复杂的因素出现。目前,人们的共识是,SBOM对许多组织来说是一个新概念,因此使讨论复杂化是不可取的。毕竟,设备软件和固件不就是软件吗? 5.1 固件和嵌入式软件   我们将这一类别分为几个讨论领域:作为操作系统的固件、嵌入式设备的固件,以及 SBOM 在某些特定设备场景(如医疗设备)中的应用。 Linux 固件 作为操作系统的固件,特别是 Linux 固件,是最容易理解的,但需注意的是,这些 SBOM 非常复杂。Linux 实际上是由数千个软件产品拼凑而成的操作系统。因此,要获得所需的透明度来了解这些软件可能会很有挑战性。但这是该领域中较容易解决的问题之一。我们为 Linux 看到的许多工具往往只是运行一个 Red Hat Package Manager(RPM)命令,除非通过大规模逆向工程处理映像,或在构建过程中在每个软件对象级别生成 SBOMs。现实情况是,由于 Linux 操作系统的构建方式存在如此多的碎片化,依赖单一实体来产生高保真度的可见性可能是一个挑战。 实时操作系统固件 实时操作系统(RTOS)固件通常更具挑战性,因为传统意义上的 RTOS 并没有文件系统。很多情况下,RTOS 更像是一个二进制文件,而不是像 Linux 风格的固件映像。对 RTOS 作者来说,这是一个可以解决的问题,我们过去也见过 VxWorks 的公共 SBOMs。然而,对于某些工业控制系统的遗留或专有 RTOS(如不使用 QNX 或 VxWorks 的系统),这个问题常常是个盲点。逆向工程可能是处理遗留软件或供应商无法提供必要可见性时唯一可行的方法。 嵌入式系统 嵌入式固件通常是高度优化的小代码。可能是运行在系统芯片(SoC)上的代码,或系统 BIOS。这些代码常常是低级代码,人类很难理解这些固件的分析。此外,为了优化和减少固件的内存占用,许多字符串和符号被剥离,这使得传统的软件组件识别方法变得非常困难。结合高安全区(如可信执行环境,TEE),这些代码运行在一个受保护的区域,不仅增加了安全性,还增加了理解软件功能和运行位置的难度。这在尝试了解软件组件的可利用性或对手如何影响软件执行时尤为明显。 设备特定的 SBOM 在考虑 SBOM 在高度监管环境中的应用时,尤其是医疗设备,需要注意认证是针对设备层面进行的。美国食品药品监督管理局(FDA)可以将胰岛素泵认证为设备,医疗设备的 SBOM 通常只有一层深度。这通常更像是软件库存而非完整的 SBOM。由于这些设备受到高度监管,变化发生得不频繁,SBOM 和分析结果通常比较静态。但令人担忧的是,这些设备的功能有时可能不太依赖于设备上运行的代码,而是依赖于云基础设施和其他外部依赖项,这对很多物联网(IoT)设备尤其如此。这些设备的外部应用程序编程接口(API)、分布在全球的支持基础设施或其他外部依赖项带来了显著风险。尽管这些设备看起来技术上很成熟,但输入和信任关系的变化创造了一个软件透明度和供应链使用案例的盲点。此外,不同设备接收更新的情况也带来了挑战。有些设备可能通过无线网络、互联网或 USB 闪存盘接收更新,这可能导致相同型号的设备在任何给定时间具有不同的 SBOMs。 5.2 开源软件和专有代码 在软件领域,代码主要分为两类——开源软件(OSS)和专有软件——这使得讨论软件供应链中的透明性变得复杂。OSS 与任何人都可以查看、使用和贡献 OSS 代码有明显不同。尽管存在一些所谓的“源代码可用”的专有软件(即源代码可以查看甚至修改,但不被认为是开源),专有代码通常不对外开放查看、使用或贡献,通常由开发各种业务软件的内部或外部的软件和技术供应商或组织控制。这种允许任何人使用 OSS 代码的能力也包括专有软件生产商,他们经常这样做。据估计,97%的软件至少包含一些 OSS 代码(www.synopsys.com/content/dam/synopsys/sig-assets/reports/rep-ossra-2022.pdf)。不仅几乎所有代码库中都包含 OSS,而且它通常可以占到代码库的近 80%。 在软件讨论中,“数字公地”一词经常被使用,它是“公地”的一个子集。公地被认为是帮助治理资源生产和集体行动的社会机构(https://policyreview.info/concepts/digital-commons)。在这种情况下,数字公地是公地的一个子集,涉及数据和信息的资源,以及数字领域中的文化和知识。当软件开发人员应用现有 OSS 许可证时,代码通常成为 OSS,这些许可证授予其他用户某些权利,这些权利通常是法律排他性授予的,例如编辑和重新分发代码的能力。一旦发生这种情况,任何获得项目数字访问权限的人都可以复制、使用、更改并提出对项目和代码的贡献。 软件产品通常与几种类型的软件许可证相关联,这些许可证通过条款、支持协议、限制和费用帮助管理其使用。软件许可证不仅定义了软件分发和使用的规则,还通常列出了最终用户在安装、保修和责任等方面的权利。在讨论 OSS 和专有软件时,OSS 软件许可证通常授予用户修改和重用源代码的能力,以及实际访问源代码本身的权限。专有软件许可证则通常不提供修改和重用代码的能力,当然也不提供对源代码的直接访问。有些情况下,软件不受许可证覆盖,被认为是公共领域软件或私人无许可证软件,如某些仍可能需要版权保护的商业应用。不遵守软件许可要求可能会产生后果,如允许版权持有人起诉或甚至使侵权者面临禁令。 常见的软件许可类型包括以下几种: 宽松许可 这些许可证对软件的修改或分发方式限制最少,但可能需要在后续分发中注明版权信息。常见示例包括 Apache、BSD 和 MIT 许可证。 弱 Copyleft  通常称为 GNU 较宽松通用公共许可证(GNU Lesser General Public License)(www.gnu.org/licenses/lgpl-3.0.en.html),它允许以最小义务链接到开源软件库,并且整个作品将在后续许可类型下分发,即使是专有许可证,要求最少。 公共领域许可证  每个人都可以自由使用和修改软件,无任何限制;这种许可证类型并不常见。 Copyleft  许可证也称为互惠许可证,在商业上可能比其他一些许可证类型更具限制性。Copyleft 允许开发人员修改许可证代码并将其纳入其他项目,甚至修改专有代码并分发,但必须在同一许可证下完成。原始软件和修改内容包含在新项目中,这使得此许可证对有商业利益的开发人员不太有吸引力。 商业/专有  这些许可证类型用于限制复制、修改和分发代码的能力。被认为是最严格的软件许可证类型之一,商业/专有许可证防止未经授权的使用软件,并且对商业利益最具保护作用。   除了许可方面的考虑,开源软件的使用非常普遍,如前所述,在专有软件和产品中也很常见。这是由于各种原因,例如节省开发时间、利用现有工作、降低成本并加快上市时间。使用开源软件代码可以使开发人员和团队专注于更多增值活动,如开发自定义代码或功能,专注于使命和业务目标。如本书简介中所述,开源软件代码几乎在每个环境中都很普遍,包括能源、金融、通信、医疗保健和国防工业基地等关键基础设施领域。尽管表面上看,开源软件的普及可能有意义,鉴于其带来的创新和社区合作,但也带来了挑战。研究发现,88%的代码库包含两年以上没有新开发的开源软件组件,81%的代码库至少包含一个漏洞,近 90%的代码库包含的开源软件不是最新版本。   这意味着过时、维护不善和易受攻击的开源软件存在于几乎所有社会领域,包括关键基础设施领域。   在专有软件方面,也存在独特的挑战。虽然开源软件通常在其来源中分配了常见漏洞和暴露(CVEs),如国家漏洞数据库(NVD),并可以使用漏洞扫描工具扫描以识别已知漏洞,但专有代码可能更难,需要其他技术来识别漏洞。此外,专有软件的源代码通常不公开,使得评估和分析不那么简单。推动 SBOMs 的使用将创造一个软件供应商和供应链在其产品中提供 SBOMs 的情况,同时还将揭示相关漏洞。   OSS 和专有软件在漏洞披露和修复方面存在明显差异。在专有软件方面,供应商通常有合同文件和协议,允许他们告知软件用户潜在的漏洞和风险影响。但在 OSS 领域则不然。因为 OSS 对所有人开放访问、使用、重用和修改,因此很难有一个集中通知或机制来通知任何受 OSS 项目或组件漏洞影响的人。这一问题因 OSS 组件被整合到其他项目和代码中作为依赖项而更加严重。这使得软件消费者必须彻底了解其环境中的软件,并警惕任何通知、漏洞和与这些软件组件相关的风险。   常有人认为 OSS 可以比专有软件更安全,因为代码是开放的,所有人都可以查看和分析。OSS 社区中一个常见的格言称为 Linus's Law 声称:“只要有足够的眼睛,所有的 bug 都是浅显的。”这似乎很直观,因为如果有足够多的软件开发人员和安全专家查看代码,bug 和漏洞的可能性会减少。尽管这在非常流行的 OSS 项目如 Linux 和 Kubernetes 上可能是正确的,但在更广泛的 OSS 生态系统中并不成立。OSS 项目数以百万计,其中一些可能有维护人员和贡献者的繁荣生态系统,而另一些则常由一小群人甚至单个人维护。一些研究表明,几乎四分之一的 OSS 项目只有一个贡献者(https://dl.acm.org/doi/abs/10.1145/3510003.3510216),更令人惊讶的是,几乎 95% 的项目有少于 10 个开发者贡献了大部分代码(www.synopsys.com/content/dam/synopsys/sig-assets/reports/rep-ossra-2022.pdf)。值得注意的是,专有软件供应商也有资源限制,这意味着公司没有无限的开发资源,通常需要优先考虑创收功能和产品增强,而不是安全活动。资源限制增加了风险,这应是所有软件消费者的考虑,无论他们是消费 OSS 还是专有代码。通过模糊性实现安全的陈旧模式也基本被淘汰,许多专家同意模糊性对对手的帮助远大于对社区的帮助。尽管如此,这并不阻止一些组织试图隐藏在模糊性后面,要么是真正相信这会带来更好的安全结果,要么是因为害怕暴露他们知道但不愿披露的低效和漏洞。   OSS 代码和专有代码之间的另一个显著差异是 OSS 的工作方式,任何人都可以消费和使用它,公开披露是通知潜在受影响消费者和各方的唯一有效方法。没有统一的 OSS 组件用户列表,公开披露允许消费者采取行动,但也要求 OSS 消费者意识到这些披露,并最重要的是,理解其 OSS 消费,以便能够采取任何措施应对风险。在专有方面,组织可以通知其客户和消费者,因为通常有协议和合同,如合同、服务级协议等。   尽管 OSS 带来了一个繁荣的创新软件解决方案生态系统,这些解决方案节省了组织的时间、资源和麻烦,但它也带来了一个复杂的现代软件供应链,具有指数级的依赖关系。研究表明,平均应用程序和项目基于使用的编程语言有近 70 个依赖关系,平均应用程序也有至少 5 个关键漏洞。许多软件消费者不了解其依赖项的全部范围,从而不了解与这些依赖项相关的漏洞。这些研究表明,尽管广泛使用 OSS,受调查的一半组织没有管理 OSS 使用的安全策略。像国家标准与技术研究院(NIST)这样的组织建议采用最佳实践,如建立管理 OSS 使用的政策,并进一步建立已知可信 OSS 组件的内部存储库供开发人员使用,而不是允许不受限制地使用外部 OSS 组件。 5.3 用户软件 用户软件与设备固件或用于管理网络和安全的企业级产品相比,往往带来截然不同的视角。通常情况下,这些软件被认为不是关键性的,因此常常未能引起足够的关注。然而,用户软件和常见工具却经常成为攻击的目标。考虑到任何软件都在用户许可下运行,并且许多组织仍然允许用户以本地管理员权限运行软件,这就表明,即使软件本身不需要管理员功能,也可以具备管理员权限。 作为行政命令14028的一部分,NIST提出了关键软件的定义,旨在确保新的软件物料清单(SBOM)要求仅限于最关键的应用程序。这在表面上是合理的,直到你意识到,软件本身并不关键,但其使用方式可能是关键的。NIST将关键软件定义为: ■设计为以提升的权限运行或管理权限的软件 ■具有对网络或计算资源直接或特权访问的软件 ■设计为控制对数据或操作技术访问的软件 ■执行对信任至关重要功能的软件(来源:www.nist.gov/itl/executive-order-improving-nations-cybersecurity/critical-software-definition-faqs#Ref_FAQ3) ■在具有特权访问的情况下操作超出正常信任边界的软件 像Adobe Reader或Notepad++这样的用户软件实际上不符合上述任何一个标准,但在特定的威胁场景下,比如用户经常解析和查看来自不可信来源的外部文档,这些软件可能引入风险或成为攻击向量。特别是Adobe经常在钓鱼攻击方案中被妥协,尽管它可能不符合关键软件的要求,但同样提供了攻击的可信路径。 对这些用户软件而言,最大的挑战可能在于应对这些威胁所需的巨大范围和可扩展性。2021年12月Log4j漏洞披露后,本书的一位作者收到了一份包含超过一百万个CPE(通用产品版本)的列表,并被问及“其中有多少个容易受到log4shell漏洞的影响?”这个机构意识到,无论软件用于何种用途,只要存在这种漏洞,就像log4shell漏洞利用所展示的那样,可能轻易扩展到更为关键的目标上。 这个例子很好地展示了供应链攻击如何以复杂的方式突破边界。这些攻击并不是直接的,而是通过信任内部用户并未正确验证其行为、宽松的访问特性等方式,即使是最无害的软件也可能为攻击开辟一条通道。我们该如何应对这些挑战呢?在达到这个目标之前,我们需要时间来广泛采用本书中提出的指导。我们希望有一天,软件供应链的最佳实践能像食品检查员确保超市内所有食品安全消费一样普遍。然而,从现实角度来看,我们也明白在行业和社会层面,我们还有很长的路要走。 5.4 遗留软件 如果我们看看开源生态系统中为解决供应链问题而推出的所有优秀项目,包括现代应用开发框架和工具,这无疑展现了一个特别乐观的前景。但是,这对于遗留软件意味着什么呢? 特别是在关键基础设施或国防领域——这些地方的系统使用寿命经常是20到30年,甚至更长——以及在没有使用包管理器的情况下生产的软件,源代码可能已经不再可用,原开发人员也许已经退休,或者更糟的是,已经不在人世了。我们面对的是一套截然不同的问题。在某些情况下,软件已经不再得到支持,或者只能定期应用定制补丁。在这些情况下,逆向工程可能是确定软件构成的唯一可行选项。不过,让我们再来探讨一下处理专有软件的另一个挑战,在遗留软件的背景下,这变得尤为有趣。 很久以前,几乎所有的软件都是专有的。虽然有时与学术界分享,或出于其他信息共享的原因,但总体来说,当我们思考当前开源软件(OSS)的定义时,带有明确定义的许可证的这种结构化概念,仅在过去大约25年左右才逐渐形成。当然也有一些例外,例如glibc(GNU C库)和GNU编译器集合(GCC),其中C编译器可以追溯到1987年。然而,当比较30多年前构建的软件和今天构建的软件时,我们会发现现代软件中有更多的组件是可以识别和理解的。 为什么开源概念如此重要呢?因为大多数应用安全工具今天并不考虑专有软件的生产过程。当前市场上绝大多数的软件物料清单(SBOM)工具只会告知您,基于已知的开源组件,您的软件是否存在漏洞。对于几乎没有或没有任何开源组件的遗留软件来说,这是一个巨大的盲点。事实上,许多SBOM工具只有在您的软件构建过程中使用了包管理器时才能发挥作用。虽然Linux已经使用包管理超过20年,但像Python和Node.js这样的现代语言的包管理工具只有大约10年左右的历史。现代的SBOM工具是根据当前的使用情况开发的,而不是几十年前在许多环境中仍然广泛使用的技术。例如,Python的包安装器pip是在2014年随Python 2.7.9引入的。 如果源代码不可用,静态分析工具就无法评估它。如果没有运行时环境进行仪表化,使用现代交互式应用安全测试(IAST)工具进行验证将变得非常具有挑战性。而且如果研究人员无法访问源代码,那么几乎可以肯定,没有公开的CVE(公共漏洞披露)能够帮助理解那些专有代码何时极为脆弱。事实上,在许多情况下,理解软件的构建方式几乎是一个黑盒子。唯一的救赎是,如果软件存在漏洞,且这不是一个新的风险。不利的一面是,这些软件往往是地球上一些最关键的软件,例如运行导弹发射井、核反应堆、水处理厂等设施的软件。 5.5 安全传输 在供应链风险管理的核心是信任的概念,或信任的验证。这包括对软件来源或出处的信任,相信它不包含超出我们风险容忍度的组件或库,相信在到达我们之前没有发生变化,相信我们即将安装的是我们所预期的产品。 安全传输机制可以有多种类型,但我们常谈的是传输层安全性(TLS),它是安全套接字层(SSL)的后继者。TLS的任务是将数据从点A安全地传输到点B,并确保高度的信任,以保证内容保持机密性和完整性没有受到损害——信任信息的发送和接收方是我们所认为的那些终端,而且数据在传输过程中未经修改。虽然TLS也用于加密和保护数据流的保密性,使得透明性的任务更加困难,但它也使得操纵数据流变得更加困难。这是一个在透明性和安全性之间有意识的权衡领域。虽然你不能再直接查看数据流中的活动,但如果你信任源头并且数据没有发生变化——也无法发生变化——那么你就可以信任到达目的地的内容。 不幸的是,这些信任决策的根源是证书颁发机构(CA)基础设施。这种机制建立了一个支撑互联网运行的信任网络。它是一个相对集中的生态系统,因为如果CA被破坏,他们签发的TLS证书或代码签名证书也可能被破坏。然而,CA机制提供了一个合理的保障,即执行这些攻击所需的难度对于大多数组织的威胁模型来说是足够的,因此基于TLS的决策通常被认为是安全的。 如前所述,对手通常会滥用加密通道来隐藏他们的恶意流量。然而,由于现代TLS协议的特性,特别是使用完美前向保密等技术,使得解密和重新加密传输变得困难,甚至对防御者来说也是如此。这将潜在的风险限制在点A和点B之间,而消除了中间30多个网络跳点作为潜在的攻击点。 同样,我们需要能够信任用于风险决策的声明。我们如何知道软件物料清单(SBOM)或构建声明是合法的?透明日志和区块链技术提供了在交易起点(例如点A)上的透明性和信任,一些实现甚至可以实现端到端的透明性和信任。但是,我们如何确保通过网络传输的数据保持不变呢?幸运的是,利用TLS隧道可以帮助回答这些问题。 那么,如果软件和声明没有通过这种方式进行保护呢?这是否意味着它们是不安全的?即使在今天,许多现代的Linux发行版也并未通过TLS来保护其软件仓库的流量,而是依赖于GNU隐私卫士(GPG)签名来确保软件的完整性。在这种情况下,你需要根据自身的风险承受能力做出判断。不过,可以说,即使在2023年,如果你要求所有软件都通过TLS进行传输,很多企业软件的使用也会受到影响。 在TLS使用更加普及之前,我们认为这可能只是针对除了最关键软件以外的一种“可选项”。尽管实施TLS存在一些挑战,但像零信任(Zero Trust)这样的运动正在推动端到端加密,作为组织应采用的最佳实践和实施方式。 此外,越来越多的组织正在努力采用双向TLS(mTLS),它使用与TLS相同的协议,但进行双向验证而非单向验证。这意味着,在建立连接和进行数据交换之前,服务器和客户端的身份都需要得到验证。 5.6 总结 总结起来,尽管推动软件透明度背后有着巨大的动力,但仍然有几个问题需要解决,而这些问题的解决可能具有挑战性。在本章中,我们讨论了一些问题,如嵌入式和遗留软件、开源软件及其各种许可类型,以及数据传输安全的需求。尽管如此,社区和生态系统中的供应商也在各自领域内不断创新和开发解决方案。持续解决这些挑战将有助于弥合软件透明度的差距,无论软件位于何处。在接下来的章节中,我们将讨论诸如云、容器和Kubernetes等技术在软件供应链和透明度讨论中的角色,以及它们所面临的一些挑战。