2.2 开发安全代码
源代码开发包括审查已批准的产品要求和设计文档,以及实现这些要求的特性和功能。 为了实现这一目标,必须按照 NIST SP 800-218、SSDF PO.1.1 中规定的编写源代码策略和程序,使用特定的计算机编程语言(例如 C++、Java、Python、RUST 等) 、PO.2.2 和 PW.1 中的解释。
选择要使用的编程语言时,您应该非常小心。 考虑该语言是静态类型还是动态类型,以及它内置了哪些保护机制来减轻漏洞并提供内存和线程安全操作。 安全软件开发遵循 Saltzer 和 Schroeder 在“计算机系统中的信息保护”中总结的原则,其中包括:
开发人员还可以集成通用核心库并重用经过组织审查的可信模块,如 SSDF PW.4 中所定义。 在许多情况下,这些指南总结了经批准的编译器安全设置以及标准化开发环境和工具的部署,如 SSDF PO.3 和 PW.6 中指定的。 根据 SSDF PS.1.1 和 PS.3,按照 SSDF PS 中的规定,在允许代码进入主存储库之前,通常会根据源代码控制系统中的指南对源代码进行版本控制和管理。 1.1 和 PW.7。 可能需要人员对其源代码进行同行评审。 有时,工程师需要在代码行和存储库之间进行比较和合并,从而在分布式团队模型中正确管理源代码。
2.2.1 内部人员修改或利用源代码
网络安全和基础设施安全局 (CISA) 将内部人员定义为“拥有或已被授权访问或了解组织资源(包括人员、设施、信息、设备、网络和系统)的任何人。
CISA 将内部威胁定义为“内部人员利用其对组织的授权访问或了解来损害组织的可能性”。 这包括有意的和无意的行为。
软件开发团队的管理者应确保开发过程防止有意或无意地将恶意代码或设计缺陷注入到生产代码中。 源代码修改可能发生在以下一种或多种开发人员场景中:
1.心怀不满的工程师
抱怨的工程师是很难检测和评估的威胁。 这些员工可能会受到外界影响的压力,或者可能怀有怨恨并寻求报复。 绩效评估不佳、缺乏晋升或纪律处分只是可能导致开发人员对组织采取行动并破坏其开发工作的一些事件。 此外,民族国家或竞争对手可以利用药物管制、失败的关系或债务来指示内部人员进行破坏。
由于开发人员对代码库了如指掌,并且通常最了解各自的编码语言、环境和风格,因此开发人员可以巧妙地设计难以检测的漏洞。 此外,访问未公开的设计细节可以提供有关包含可利用安全缺陷的薄弱架构或代码的知识。
一旦实现并注入到构建基础设施中,内置漏洞就会被编译、签名和散列,以通过高级安全验证检查,而不会出现任何妥协迹象。
2.缺乏训练有素的工程师
没有经过适当的安全设计和编码实践培训的工程师可能会无意中在源代码中引入漏洞,这些漏洞一旦提交到源代码存储库就很难检测到。 漏洞的类型包括从缓冲区溢出到逻辑缺陷,后者更难以检测。 这些“零日漏洞”可以长时间隐藏在产品中,为发现它们的对手提供了一种简单的入侵手段。
3、利用软件开发功能(后门)
开发人员有时会向其产品添加调试功能,以方便通常在初始化之前执行的故障排除、安装或问题报告过程。 在许多情况下,这些功能是特权操作软件源更新失败,允许开发团队获取统计数据和日志并发出远程命令来重新配置正在开发的系统。 虽然这些开发人员功能可能很有帮助,但它们通常紧密集成到产品的核心组件中并且难以删除。 在某些情况下,它们会导致组件被“滥用”以促进正在使用但未在产品中正式设计的工具和功能。
这些功能通常计划在发布前完全删除,但在某些情况下不会删除,因为由于核心组件的集成和工作水平,在接近产品预定交付时删除它们存在风险。 这些功能可以在发布时禁用,但当保留在已发布的产品中时,它们就会面临被发现和利用的风险。 另一个开发问题是,只有应用程序的部分或功能需要权限升级,但整个应用程序配置为以执行单个任务所需的权限运行。 特权提升后应立即完成特定功能以减少攻击面。
4.入侵远程开发系统
开发环境中的常见做法是允许员工远程开发并将其外包给第三方开发人员。 许多远程开发人员在家里或分支机构工作,使用通过 VPN 连接的公司提供的机器和资源。 使用此环境时,远程办公室成为组织网络的延伸,开发人员可以访问标准工作环境提供的所有开发资源,包括创建、编译和签入源代码更改。
虽然普及这种工作环境有很多好处,但远程工作也有其风险。 家庭或远程办公室网络可能无法提供与本地公司设施相同级别的保护。 此外,远程办公员工可能更倾向于使用受限制的网络应用程序,例如社交媒体、网上冲浪和游戏,在某些情况下为了方便而删除本地计算机保护。 在这种环境中,这些系统受到损害,使得攻击者能够使用远程环境中的后门来访问和修改组织受保护的源代码基础设施内的源代码。
5. 使用已终止或不活跃用户的剩余凭据
当员工被解雇、分配到另一个项目或长时间缺勤时,他们的权限和帐户通常仍然可用,并且可以在帐户所有者不知情的情况下执行恶意活动。 在这种情况下,帐户所有者没有监控其使用情况,也不知道使用它执行的任何恶意活动。 以这种方式未经授权使用帐户将向原始帐户所有者授予对所有开发资源的平等访问权限。
建议的缓解措施
特定流程有助于降低开发项目中有意或无意注入恶意代码的风险,包括:
1. 实施平衡的认证源代码签入流程控制
保护源代码存储库及其内容的基础是使用访问控制方法,并使用验证过程来确定签入是否“良好”。 访问和验证始于良好的源代码管理 (SCM) 原则并跟踪对源代码存储库的修改。 这些原则包括更改代码库的操作历史记录以及解决多个贡献者合并更新时的冲突。 例如,免费开源软件的获取流程、开箱即用的商业软件源代码组件以及安全软件代码库的管理摘要如图3所示。
图 3:安全源代码存储库流程
安全源代码库应首先不断地在添加的组件中寻找新的漏洞和更新。 保存所有开发人员和组件下载的日志。 如果某个组件由于新的漏洞或更新而被标记为将来使用,则应保留开发人员和已下载组件的日志。 如果某个组件因漏洞或未来更新而受到警告或警告,下载该组件的开发人员将自动收到通知以解决问题。 这样,当新的漏洞出现时,哪些程序/项目受到影响就一目了然。
至少,源代码控制系统应使用行业认可的多重身份验证 (MFA) 进行保护,该身份验证不仅记录签入,还记录对安全存储库的所有访问。 签入时,会创建一个日志,记录多重身份验证开发人员 ID、修改的文件以及签入的日期和时间。 根据复杂性、安全要求、可用开发资源和时间限制,在实施平衡的源代码签入流程时考虑以下几点:
同行/领导评审
工作及生产部
为了控制所生产的软件的质量,维护两个或多个开发分支。 在正常的软件开发过程中,所有代码都可以存储在工作、一般和开发分支中。 随着组件开发的进展,支持所交付功能的源代码由高级工程师进行编码、测试和审查,以确保满足功能集而不会出现任何功能漂移。 由高级工程师、构建工程师和设计师组成的开发工作完整性保证团队将批准的代码移至生产部门。 生产分支,有时称为发布分支,用作构建发布产品的唯一存储库。 该分支应由审阅者保护,并由供应链管理人员在持续集成/持续交付 (CI/CD) 中使用 SAST 测试来强制执行。 分支准备和转移的过程可以概括为:
开发人员在开发部门工作。
当源代码经过审查和批准后,领导层会将软件推送给 QA 部门。
QA 个人/团队测试 QA 分支。
一旦集成代码经过测试和批准,它就会被转移到生产分支。
产品分支的访问权限仅限于一小部分构建和开发团队成员。 用于创建生产产品的所有构建都来自存储库的生产分支。 产品发布后,应标记并锁定产品分支以进行有限的客户访问或只读访问。 实施锁定过程可确保安全且可重复的构建。
2. 执行静态和动态安全/漏洞扫描
对系统的所有组件执行自动静态和动态漏洞扫描,每个提交的更改都是构建过程的安全性和完整性的关键,并验证产品是否已准备好发布。 这种自动扫描以及其他与安全相关的扫描可以执行代码分析,以确定受限制的应用程序编程接口 (API) 是否在源代码评估阶段包含缓冲区溢出或内存泄漏等漏洞。 在提交代码之前,执行静态分析、扫描机密凭据,并在 CI/CD 期间从代码库中阻止机密凭据。 这些静态扫描技术的复杂程度和完整性差异很大。 这些工具应该由测试团队以及本地开发工程师使用。 最安全的开发流程推荐这种方法。
独立的和更高质量的扫描工具也应该在生产构建环境中使用。 还应该注意的是,静态分析程序在静态类型语言(例如C++)上工作得更好,因为代码中使用的变量类型在编译时是已知的,而动态类型语言(例如Python)在运行时解析变量类型。 当功能和组件完整并能够运行时,动态测试可以发现其他安全漏洞。 这些通常是用户输入错误或恶意注入,只能通过运行时测试才能发现。 对于 Web 应用程序,应使用交互式应用程序安全测试 (IAST)、动态应用程序安全测试 (DAST) 和运行时自我保护(RASP 应用程序自我保护)工具,请参阅 NIST 800-53 v5。 由于 IAST 工具往往比 SAST 工具有更多误报,尤其是在 Web 应用程序中,因此在此环境中实现测试要求时,鼓励使用内省 SAST 工具。
3. 每晚构建安全性和回归测试
为了确保开发过程的完整性和质量,应执行夜间构建,包括手动和自动安全及回归测试。 测试用例应该在软件设计过程中实现,并扩展到编码过程,以验证“好”和“坏”场景中的所有功能区域。 使用此过程,可以识别并解决任何缺陷或更改,无论是恶意的还是无意的。
带有回归测试的夜间构建应由 QA 工程师操作,并由构建工程师合并到构建环境中。 这与开发人员自己的自动化单元测试的情况不同,后者可以在编码期间手动运行,也可以在组件的“构建”过程中自动运行,这通常是开发人员的责任。
当回归测试失败时,会自动发送日志和电子邮件通知,以帮助通知和跟踪问题发生的时间和地点。 每晚构建过程也是一个很好的性能矩阵,用于评估开发人员的能力以及对安全和开发过程的合规性。 有关产品构建的更多详细信息,请参阅第 2.4 节强化构建环境,其中记录了本地开发构建与产品生产构建的比较。
4. 将功能映射到需求
使用安全设计实践(包括威胁建模和攻击面分析)与系统交互时,构建产品的所有组件和功能非常重要。 一旦识别并缓解了所有安全风险,架构和设计文档就会最终确定并分发给各个开发团队执行。 生成的初级设计和功能规范直接映射到给定的架构和高级设计,并规划出开发任务和时间表。 在编码和系统实施过程中,必须非常小心,以确保所有开发工作都映射到特定的系统需求,以便不会发生破坏产品完整性或注入漏洞的“功能漂移”。
正式、非正式和同行评审有助于确保添加到存储库的代码满足特定要求,并且仅满足这些要求。 这些审查还可以识别作为较大包或组件功能的一部分包含的模块和未使用的代码。 如果可能,只需要产品中包含的模块。
此外,开发人员应删除未使用的模块以及超出要求和设计文档的代码。 将开发人员工具(例如帮助调试、配置和监控的工具)的添加限制为仅批准用于系统设计的工具,也可以减轻攻击面。 尽快报告和解决功能漂移问题也可能会有所帮助。
此外,构建环境应支持对所有系统插件的扫描和检测。 结果应与允许列表相关联,以确保不会添加未经授权的组件。 这些扫描生成的工件描述了产品中包含哪些组件和软件功能,更重要的是,确保所有组件都经过分析,以便理解和记录每个组件的风险。
5. 优先考虑代码审查并审查关键代码
代码审查使用正式和非正式两种不同的流程进行,并在开发生命周期的不同阶段实施。
代码审查应该优先考虑,至少应该使用正式和非正式的审查流程来优先考虑、识别和审查最关键的代码。 关键代码包括以下几个部分:
除了正式和非正式的代码审查之外,还应该部署自动化代码审查工具以提供完整的代码审查覆盖范围。
在开发过程中,当测量阶段或检查点完成时,内部开发团队会使用非正式的代码审查流程。 非正式审查用于确保遵循安全编码策略和流程,并且在组件的初始设计期间,源代码审查满足设计和功能要求。 这些审查由开发团队成员(包括项目负责人和高级开发人员)进行,以确保开发过程中的安全性和完整性。 尽管是非正式的,但进行代码审查的过程会生成有关审查领域和结果的文档,可用于帮助衡量开发团队的结果。 非正式的代码审查也被用作培训工具,以教育团队成员如何实施安全编码实践。 此外,非正式的代码审查可用于衡量代码审查过程和开发人员可交付成果的质量。
正式的代码审查可确保使用最佳实践安全地集成关键组件。 这些审查重点关注系统完整性、设计和架构,同时解决所有功能、安全性和可靠性方面的问题。 他们还确定了任何潜在利用或入侵的担忧领域。
工程团队(通常包括 QA 成员、构建专家、设计师和建筑师)经常进行正式的代码审查。 在正式的代码审查中,在审查源代码之前,组件的所有者会描述该组件的功能及其与系统中其他组件的交互。 指定人员保存详细记录并跟踪产品核心组件的审查。
正式代码审查的结果是一份活动清单,其中列出了在产品发布之前必须解决的问题。 正式的代码审查通过共享产品设计和实现的知识来协助开发工作,以增强构建和开发环境的测试需求。 正式的代码审查还允许产品管理团队衡量产品发布的准备情况,并确保在发布之前满足所有要求。
6.安全软件开发/编程培训
正如第 2.1 节“建议的缓解措施”“评估和培训”小节中所总结的,开发人员应接受持续培训,以了解公司发展所需的安全开发实践。 该资源还必须在开发生命周期内可用,以便开发人员能够联系专家并解决他们可能对特定安全问题、实践或漏洞的疑问。 应在日常开发活动中利用安全专家来促进同行和源代码审查、对个人进行公司安全实践培训并评估他们的知识。 实施良好的同行评审流程使工程师能够防止缺陷、最大限度地减少安全漏洞并促进团队协作和知识共享。
七、强化发展环境
就像构建环境一样,开发环境也必须硬化。 第 2.4 节强化构建环境中定义的缓解措施也适用于开发环境。 然而,虽然生产构建系统通常驻留在访问权限有限的受保护的分段网络上,但开发构建环境可能驻留在不太隔离的端点系统上。 例如,许多开发环境允许远程VPN访问内部开发机器,以方便远程工作人员并允许他们参与开发活动。 在这种情况下,从远程位置连接公司的开发环境时,必须使用VPN和MFA来保护开发环境。 应安装端点安全软件来预防、检测和响应针对主机系统的威胁。 除了 VPN 之外,实施者还应考虑使用“跳板”,该系统充当安全性较低的远程主机和受保护的开发环境之间的门户。 这允许对所有活动进行持续监控,并为远程开发人员提供保护和/或限制访问和操作权限。 需要在与产品开发相关的所有开发环境中评估威胁模型和漏洞。
2.2.2 开源软件管理实践
开发人员在应用程序开发中经常使用开源代码,开源代码库中可能存在多个易受攻击的依赖项。
建议的缓解措施
开发组织应使用专门的系统来下载、扫描开源代码库并定期检查是否存在新的、更新的、已知的或新版本的漏洞(参见上面的图 3)。 与所有软件一样,我们强烈建议教育开发人员考虑使用开源软件、闭源软件,并改进最佳实践缓解措施。 详细信息请参阅 SSDF,特别是 PW.4.1、PW.4.4、PW.4.5 和 PO.1.3。
2.2.3 安全开发实践
软件开发团队的经理应确保生成、测试和保存源代码的开发过程是使用定义明确且安全的实践来完成的。 这有助于建立对所使用的工程工具链和流程的信任。 这些做法解决了以下安全问题:
建议的缓解措施
以下是实施安全开发实践的建议活动:
1. 保护开发者环境
在确保开发环境的完整性时,必须注意强化构建管道中的开发系统,如第 2.4 节强化构建环境中所定义。 此外,所有开发系统必须仅限于开发活动本身,不得用于任何其他活动(例如电子邮件),并且只能用于工作,不得用于个人用途。 如果可能,开发系统应该没有互联网访问权限,并部署为本地虚拟系统,仅提供主机访问。 即使仅供本地开发使用,开发过程中安装的所有工具系统也必须经过预先批准,包括调试器、测试工具、漏洞扫描器和建模软件。
2. 使用安全开发构建配置
许多漏洞使用常见的入侵技术,例如缓冲区溢出、面向返回编程 (ROP) 执行小工具、延迟动态函数加载和重写软件异常处理程序。 许多这些技术、编译器、汇编器、链接器、解释器工具已经扩展到包括减少这些风险的防御措施。 以下是为减少入侵方法而应部署的构建链防御技术的列表:
堆栈 cookie - 防止堆栈覆盖,
地址空间布局随机化 (ASLR) - 防止 ROP/硬编码 IP 引用,
SEHOP - 防止 SHE 挂钩,
数据执行保护 (DEP) - 堆栈/堆执行保护,
无执行位 (NX) - CPU 标志执行阻止内存位置,
静态库——防止预加载恶意动态库,
二进制文件剥离 - 从二进制文件中删除符号使文件更难以逆向工程,
硬件特定阻止 - 可以基于内置硬件支持其他阻止。
虽然上述阻止措施对于确保正在开发的软件的运行时保护至关重要软件源更新失败,但开发团队还应为最终用户提供推荐的环境,使他们的软件可以安全运行。 例如,许多防病毒产品提供行为分析引擎来提供额外的安全检查,例如:
堆喷射缓解 - 监视频繁的目标堆地址,
堆栈枢轴检测 - 检测 ROP,
ROP调用检测——JMP/RET(非常规程序流)的检测,
DLL注入检测——动态链接库(DLL)位置和签名验证,
空页检测 - 解锁漏洞,
Root-Kit检测-块地址挂钩,
行为启发式 - 检测异常的 CPU、内存和资源活动。
同样重要的是要注意,虽然解释型语言通常不会面临上述漏洞的风险,但解释器本身的实现及其使用的底层系统库却面临着上述漏洞的风险,因此这些缓解措施也适用于它们。
3.使用安全的第三方软件工具链和兼容性库
在开发人员的构建过程中,各种任务通常被集成到集成开发环境(IDE)中。 其中许多环境都是独立的,允许在工具内执行所有开发活动,包括编码、编译、链接、打包和调试。 IDE 甚至可以提供将源代码签入存储库的功能。 很多情况下,这些IDE支持多种编译语言和环境,并且可以安装插件来扩展IDE的功能。 由于复杂且不受信任的源代码,IDE 可能会受到损害,从而导致不安全的本地开发环境。 为了确保开发过程的完整性,开发人员环境中使用的所有 IDE 及其相关插件在并入任何开发人员机器之前都必须经过预先批准、验证和漏洞扫描。
构建环境可能需要使用特定于操作系统的实用程序和命令。 例如,在开发人员主机上的构建过程中,Windows 环境可能需要 Linux 操作系统命令。 这样的构建环境可能需要在开发主机上安装第三方操作系统工具和实用程序,以提供开发环境和生产构建之间的兼容性。 此外,许多开发环境需要 API 翻译库来促进两个不同操作系统(例如 Windows 和 Linux)之间的通用编码环境。 工具链和兼容性库可通过商业和开源软件获得。 兼容性工具链和库还需要在开发采用之前通过漏洞评估。
2.2.4 代码集成
开发经理希望确保集成到交付产品中的组件和软件在部署环境中经过测试。 此过程包括合并所有必需的依赖项,包括添加到单个系统所需的源代码、组件以及元数据和实用程序。 在代码集成期间,开发人员将确保代码成功构建并监视和评估运行时行为。 软件集成应使用推荐的零信任原则 NISTSP800-207。
建议的缓解措施
所有第三方模块都应进行 CVE 测试。 软件组成分析工具可以帮助自动化此过程。 开发团队还应该订阅来自国家网络意识系统和其他来源的警报和报告,以获取最新的软件漏洞信息。 模块完成漏洞检查后,可以将它们添加到开发人员或开源代码审查委员会 (OSRB) 存储库中以供下载。 该可信存储库应继续测试以识别模块内新报告的漏洞。 它还应包括向最终用户提供漏洞更新和/或补丁的流程。 应用程序包括来自其他来源的代码,有时会稍加修改或添加出于特定使用目的的集成代码。
安全依赖性分析器和许多其他工具和服务可以帮助检测具有已知漏洞的重用组件。 这些活动通常在集成开发环境 (IDE) 中进行,使用组织的安全编码实践和指南,例如 SSDF 的 PW.3.1、PW.3.2 和 PW.4.1。 代码集成应使用零信任原则来实现。 不应暗示信任,因此重要的组件和功能应检查代码中的使用和访问权限,并仅在必要时升级权限。 开发人员应确保代码和构建集成过程是可重复的。 开发人员和 QA 工程师可以提供自动化回归测试,以确保组件正确集成并实现设计和需求文档中指定的功能。 他们还提供额外的静态和动态扫描工具,以根据 SSDF PW .5.1 和 5.2 定义的条件检测开发代码中的编码错误和安全缺陷。
2.2.5 客户报告的缺陷/漏洞
软件开发团队的经理应确保他们开发的软件不存在高风险的已知缺陷和漏洞。 当客户发现并报告漏洞时,开发团队应响应事件并提供组件更新,以减轻与缺陷或漏洞相关的风险。
建议的缓解措施
供应商应该有一个开放的流程来接受来自客户和第三方研究人员的潜在缺陷和漏洞的报告。 供应商应使用来自受信任组织(例如网络安全和基础设施安全局(CISA))的自动漏洞通知来及时接收有关最新高风险威胁的警报。 所有通知均应根据其与产品的关系进行评估,并根据风险评估确定优先级。
然后应指派一名工程师来审查、诊断和解决 PW.8、RV.1.1 和 RV.1.3 中定义的问题。 为了减少攻击面,应实施一个流程来识别漏洞类别并检查可能受同一类别已识别事件影响的其他产品功能和组件。 应根据组织的内部漏洞管理策略向客户提供及时响应,该策略应基于行业最佳实践文档,例如 NIST SP 800-216 指南。 Use secure channels to update software according to the requirements and regulations of SSDF RV.2.1 and RV.2.2. Updates are also provided to all customers of the product, and a description of the defect or weakness and its resolution is communicated to the customer. It can also be automatically applied to products based on customer-configured update policies.
2.2.6 External development extensions
once released, product functionality can be expanded by product development teams outside of the initial development team. In many cases, this external development team, along with the developers responsible for the product, may need to add additional functionality to the product or customize it to specific customer needs, implementing functionality that is not met by the product's owner. This external development team may be a solutions team within the company that produces the product or a value-added reseller (VAR). An example of this type of activity might be adding a required authentication method to an existing product.
When this activity occurs, modifications to the product can include adding software packages to support the functionality, as well as graphical user interface (GUI) changes to enable and manage the new functionality. During this activity, new development work, new packages deployed, or APIs not used when modifying the design may introduce vulnerabilities.
建议的缓解措施
Where possible, product extensions must follow all secure development practices defined by the original product development in accordance with SSDF PS.1.1, PW.4.1, PW.4.2, PW.5 and PW.7. Additionally, a software bill of materials (SBOM) should be provided detailing the added packages and software. If a signature is required, the certificate used (if not from the vendor of the same product) must be clearly identified. Modified modules in the original code must be clearly marked in the new SBOM. The original component information and owner, together with new information describing the newly modified module, must be clearly marked, as required by SSDF PS.1.1.
When a problem arises, the Security Incident Response Team (PSIRT) must be available and ready to assist end users, even if the cause of the problem is related to extensions added on request in SSDF RV.2.1. In many cases, a value-added reseller (VAR) will serve as the "middleman" between the customer and the product security incident response team to help resolve issues.
Feedback to engineers to resolve issues must be aggregated between the customer and external development groups to provide timely, accurate information to resolve issues. Any code modifications due to vulnerabilities in the provided APIs and functions must be corrected and released to all customers. These activities provide the following mitigation measures consistent with SSDF activities:
1. PS.1.1 - Store code and executable files, review and approve all changes.
2. PS.3.2 - Create and maintain an SBOM for each package generated.
3. PW.4.1 - Obtain safe and reliable components.
4. PW.4.2 - Create secure software components in-house.
5. PW.5 - Generate source code according to secure coding practices.
6. PW.7 - Review and/or analyze human-readable code.
7. RV.2.1 - Analyze each vulnerability to gather sufficient information to plan its remediation.
(超过)