在影子软件供应链中平衡速度与安全

影子软件供应链,其许可不明,代码风险高,几乎无法与其他贡献区分开来。
首页 » 博客 » 在影子软件供应链中平衡速度与安全

现代包管理是当代应用程序最具变革性的方面之一。由于库处理了重复性的繁重工作,应用程序团队取得了历史性的效率,从而使企业开发人员能够专注于高层次的领域特定逻辑。Javascript、Python、Golang 和其他语言的爆炸式增长与可用的庞大开源库生态系统紧密相连。

这些包管理器使跟踪安全和许可问题的依赖项变得容易。软件所有者可以相对轻松地组装具有嵌套依赖项等的依赖树。虽然依赖项的更改可能会无意中产生重大的下游影响(例如,Ruby on Rails 依赖的库切换到 GNU Library General Public License version 2.0 (GPL v2) 导致大多数 Rails 项目的许可不兼容),但这些下游影响可以被跟踪这一事实证明了成熟的软件供应链管理系统。

这些互锁组件的管理取决于高效的收集和通知。问题在于,影子软件供应链,其许可不明,代码风险高,几乎无法与其他贡献区分开来。

Stack Overflow 和现代软件工程师

Stack Overflow 是当今软件工程师的宝贵资源。它是学习如何解决您可能不知道如何解决的问题的好地方。然而,年轻的程序员往往过度依赖第三方代码片段网站。

不仅仅是 Stack Overflow;无数的博客和 YouTube 教程涵盖了大多数程序员需要的大部分内容。如果一个人知道在网上搜索什么,就可以相对容易地获得软件工程本科学位。从在线资源复制和粘贴已成为年轻程序员模因文化的核心。虽然这些工程师应该尝试通读并重新实现代码(遵守安全最佳实践),但复制和粘贴非常容易,以至于几乎没有感知到的需要理解代码的作用,只要它能工作即可。

可追溯性和碎片化代码

影子源代码与开源的区别是什么?为什么它令人担忧?影子源代码之所以“影子”,是因为它是不可信任、不可追溯、无法与内部开发的代码区分开来的代码。相比之下,第一方代码至少涉及一个理解正在实现内容的人。当使用第一方代码时,至少有一个内部人员理解它。团队可以将更改纳入其软件开发生命周期 (SDLC) 实践中,以便符合安全标准。这些可以包括威胁建模和开发最佳实践,以减轻格式错误的数据错误。

开发人员在使用第三方代码时,会优先考虑方法的输入和输出,无论它是从开源库还是在线资源获得的。只要输入和输出与他们的期望相符,就不会过多地考虑内部结构,从而忽略了格式错误的查询带来的风险。

大型开源库通过接受严格的安全审查来降低风险,尤其是来自大型采用者的审查。像任何软件一样,都会存在错误和漏洞,但它们更难被发现。如果安全研究人员或通过漏洞赏金计划发现了错误,包管理可以相对容易地进行更新。虽然会出现一些修复噩梦(如 Log4Shell),但这些情况相对罕见。

大规模开源和影子源代码之间的根本区别是什么?影子源代码的另一个缺点是安全研究人员更难发现,并且缺乏适当的通知基础设施。在线示例通常尽可能简单明了,同时尽可能少地依赖库。这是一种危险的组合。

对于在线贡献者来说,安全不是一个问题,也不是一项责任。编写安全代码对于无偿论坛上的人来说是不必要的,而且浪费时间。在线上,简单的解决方案会推动参与度。为了追逐点击和分享,拥有博客或 YouTube 频道的人会积极地被激励发布未准备好用于生产环境的示例。

人工智能问题

影子源代码并不是什么新鲜事物,但还有另一个因素将导致它大规模爆发:生成式人工智能。我最早在公开测试版早期使用了 GitHub Copilot。虽然我经常仍然手工编写代码以防止我的技能退化,但当需要快速编码时,它是一个很棒的工具。

与此同时,生成式人工智能使次优的开发实践成为可能。开发人员可以轻松生成代码,这意味着实现可用的解决方案可以快速而轻松。因此,标准化开发流程和工具的优势可能变得不太明显或不引人注目。

标准化为安全性、可靠性和质量带来了许多好处。这些好处包括:如果发现错误,则更容易在整个代码库中进行修复;贡献者切换团队时,入职时间更短;开发速度更快。开发速度是投资标准化的最令人信服的理由。

人工智能消除了这种特定优势,同时保留了其他优势。事实上,在注意到我的软件演变成无法管理的意大利面条式代码,其中包含大量重复(但略有不同)的代码块后,我已经停止在长期可持续性很重要的项目中使用 Copilot。

如果发现错误或漏洞,广泛而快速的修复仍然是一个令人担忧的问题,而微小而无意义的差异会增加发生错误或漏洞的风险。因此,考虑到这一点,当自我利益的激励逐渐减少时,您如何缩小影子代码并促进标准化?

前进的道路

应用程序安全团队必须根据组织文化和目标调整其开发人员关系策略。然而,总的来说,我认为 AppSec 团队应该尝试支持和指导开发人员走向更安全的代码库,而不是采取高压手段。(更多内容将在以后的文章中介绍,以免我在这里离题太远。)对于大多数团队来说,最好的方法是使阻力最小的路径也是带来最有价值的安全效益的路径。

一次做好,一次做对

长期以来,我一直支持“一次做好,一次做对”的开发理念。我在高中机器人团队中创造了这个短语,以描述我们对高质量和可靠代码的投入,即使它需要更多的前期投入。如果您第一次以正确的方式做事,那么您最终将获得比您拼凑一个快速解决方案并在以后需要替换它更好的解决方案,并且花费的时间更少。

安全和软件领导层应推动一种重视为高质量产品花费更长时间的文化,而不是“快速行动,打破常规”的态度。快速行动是好的,但用户对事物崩溃的容忍度很低。相反,团队应该强调构建一个坚实的基础,以便在其之上进行更快的迭代。这样,开发团队就可以继续在高层次上思考,但对底层技术充满信任。

如果底层技术之一出现问题,可以修复一次并推送到各个应用程序中。由于可以投入更多精力来开发一些核心技术,因此发生事件的个人风险远低于部署所需最终目标的几种不同变体的情况。

一套强大的库通过提供一种简单且值得信赖的方式来与常见操作进行交互,从而减少了对影子源代码的需求。例如,生成式人工智能可能会使用字符串连接来构建结构化查询语言 (SQL) 查询。如果应用程序使用对象关系映射 (ORM),则 ORM 会减少与直接 SQL 交互的需求,并为输入清理提供统一的位置。

转向更高级别的抽象,开发人员可以获得更好的开发人员体验,安全团队有更多机会影响数据流。然后,开发人员会出于自身利益而与首选方法进行交互,因为它比使用影子源代码更方便。

推动采用

面向服务的安全性可以通过 API 代理、第三方云提供商、开源库或第一方内部库来实现。它通过使用库和服务简化了开发人员体验,同时也将安全团队与开发团队对齐。

开源库

开源库提供了许多有用的抽象,对于大多数团队来说,它们是一个非常好的起点。应用程序所需的大部分功能都不会提供任何有意义的竞争优势。因此,冗余的开发工作纯粹是不必要的重复。

虽然开源在为企业应用程序提供动力方面取得了广泛的成功,但在库的采用、创建和标准化方面的进一步投资可以帮助提高安全性和生产力。这仍然需要适当的软件供应链管理,但如果可以为开发人员提供更简单的界面,而无需依赖影子源代码,这将提高可追溯性。

云提供商

云提供商可以是快速标准化某些技术并将大部分安全工作卸载给第三方的简便方法。对于小型公司或希望保持小型 IT 和安全团队的公司而言,云服务是在安全代码之上快速构建的最佳方法之一。他们承担了部分安全责任(尽管仍然需要安全的实施),并提供了非常流畅的开发人员体验。

然而,云提供商并非长期增长的理想解决方案。它们会造成严重的锁定,如果产品被弃用或变得过分昂贵,可能会带来麻烦。成本是另一个主要问题,尤其是对于非常大的组织而言。计算资源是一个竞争非常激烈的领域,因此利润率很小。相反,云服务提供商通过服务和 API 来证明其价值。

成本可能会迅速累积,而企业采购的官僚世界意味着您最终可能会为首选供应商的劣质产品支付更多的钱,而不是您本可以获得的。在某些情况下,云服务肯定有价值主张。然而,随着成本持续增加,对于许多组织来说,云服务将变得越来越不合理。

内部抽象

当公司开发许多不同的产品或处于受监管的环境中时,内部抽象会提供价值。这些抽象可以更好地针对特定的业务约束进行定制,从而创造更好的开发人员体验。然而,它们比开源或云解决方案需要更大的投资。

内部抽象的一个良好用途是作为受信任的开源库的包装器。通过这种方法,既可以有一个经过良好测试的开源库,又可以为安全工程团队提供更多机会来引导数据流并添加自己的控制。包装器库的开发人员体验可能比核心库更好。

代码审查

自动化和手动代码审查是软件安全的重要步骤。作为合并批准过程的一部分,审查人员应查找可能可以通用化但实际上是内联的功能。应特别关注在代码库的多个部分重复出现的内联、高风险功能(例如数据库查询)。

面向安全的生成式人工智能

我并不声称理解生成式人工智能的工作原理。然而,由于有主导行业的面向安全的合作伙伴(微软和谷歌),代码生成可以被推动以强调强大的安全实践和宽松的许可。

在简短的测试中,ChatGPT 和 Google Bard 倾向于输出高度不安全的结果,但在提示中添加“安全地”后,安全性会大大提高。例如,在 ASP.NET 代码的测试中,添加“安全地”将 SQL 查询中的原始字符串连接更改为具有内置清理功能的特定于语言的 SQL 构建函数。)

他们还应该对大型、许可宽松的项目进行更重的训练权重。影子源代码的许多问题在于,提供的代码未经测试,并且许可不明。人工智能生成的许可仍然不明朗(并且博客和论坛等来源无济于事),但是,随着许可问题在法庭上得到解决,跟踪归属并优先考虑宽松许可将有所帮助。

下一步是什么

影子源代码在在线论坛中非常普遍,并将随着生成式人工智能的普及而继续增长。生成式人工智能的主流采用将使生成结构不良和编写不佳的代码变得更容易,从而导致更多易受攻击的应用程序并延长修复时间。由于维护糟糕的代码库变得更容易,团队需要更有意识地坚持最佳实践。

鼓励最佳实践的最佳方法是使最安全的路径也成为开发人员最省力的路径,从而自然而然地采用最佳实践。

照片由 Zac Ong 拍摄于 Unsplash

作者

  • Alexander Beaver

    Alexander 是罗切斯特理工学院的计算安全专业学生。他专注于安全软件开发和安全运营。过去,他曾为 Paramount Global 和 Cisco Jasper 开发主动检测机制和自动化修复工作流程。他还为一家主要的信用评级机构开发了网络安全风险管理培训。他对软件开发的热情几乎贯穿了他的整个生命。工作之余,他维护一个博客,在博客中谈论网络安全和开源,并且是一位业余摄影师。

    查看所有文章

如果您喜欢这篇文章,您可能也会喜欢这些