为增强软件供应链安全,NIST 发布《开发者软件验证最低标准指南》
编译:奇安信代码卫士
数字化时代,软件无处不在。软件如同社会中的“虚拟人”,已经成为支撑社会正常运转的最基本元素之一,软件的安全性问题也正在成为当今社会的根本性、基础性问题。
随着软件产业的快速发展,软件供应链也越发复杂多元,复杂的软件供应链会引入一系列的安全问题,导致信息系统的整体安全防护难度越来越大。近年来,针对软件供应链的安全攻击事件一直呈快速增长态势,造成的危害也越来越严重。
为此,我们推出“供应链安全”栏目。本栏目汇聚供应链安全资讯,分析供应链安全风险,提供缓解建议,为供应链安全保驾护航。
注:以往发布的部分供应链安全相关内容,请见文末“推荐阅读”部分。
这11条技术建议如下:
建立查找设计层安全问题的威胁建模
一致性自动化测试,将手动测试最少化
利用静态代码扫描查找重要漏洞
利用启发式工具查找可能存在的硬编码机密
使用内置检查和防护措施
“黑盒”测试用例
基于代码的结构性测试用例
历史测试用例
模糊测试
在可能的情况下使用 Web app 扫描工具
解决被包含代码(库、程序包、服务)
NIST 在文档中指出,为确保软件是充分安全的,软件必须得到良好的设计、构建、交付和维护。开发者在软件开发生命周期尽早地经常、全面地进行验证是软件安全保证的一个重要因素。在最高的概念层,我们可将验证视作提升软件质量的心智训练。正如 NSIT 在发布的安全软件开发框架(SSDF)中所提出的那样,验证用于“识别漏洞并验证和安全要求的合规性”。ISO/IEC/IEEE 12207:2017 标准指出,有时在非正式情况下,验证被称为“测试”,包含很多静态和主动的保证技术、工具和相关进程。要确保高级别的软件质量,必须结合使用多种方法。
NIST 指出文档推荐的是软件厂商需执行的最低软件验证标准。没有一种软件安全验证标准能够在包含所有的软件类型且在支持有效验证的同时是具体且规范的。该文档为软件厂商提供在创建自身进程中使用的指南。要达到最佳效果,该进程必须是针对软件产品、工具链和开发生命周期模型的定制化进程。
NIST澄清或解释了该标准文档中术语的适用范围。
“软件“是指可执行的计算机程序
本文档未包含起着辅助作用但重要的材料如配置文件、文件或执行权限、运营程序和硬件。
本文档并不解决特定的测试问题,而是给出最低标准的软件测试技术,而这里的“软件”和网络以及平行/多线程软件有关。安全关键的测试要求由响应的法规部门解决。
虽然美国总统发布的行政令中使用了“软件源代码”一词,但意图更为宽泛且包括一般意义上的软件,如二进制、字节码和可执行文件如库和程序包。我们认为不可能像检查人类可读的源代码那样全面有效地对这类软件进行检查。
除非为测试做参照,本文档不考虑对安全功能要求和规范的验证或确认。
非正式术语“测试 (testing)”指的是对软件执行的确保软件按预期运行的任何技术或程序,它具有必要的属性且不存在重要漏洞。然而本文档使用的是 ISO/IEC/IEEE 中所用的“验证 (verification) ”术语。除了包括狭义上的“测试”概念即动态分析或运行程序外,验证包括还多种方法如静态分析和代码审计。
本文档不包括对软件开发中的其它关键软件保证因素的验证,如程序员培训、专业知识或认证、之前或之后软件产品的证据、进程、指令正确或基于模型的方法、供应链和编译保证技术以及在运营使用中报告的失败情况。
“验证”假定标准的语言语义、正确和健壮的编译或解释引擎以及可靠且准确的执行环境如容器、虚拟机、操作系统和硬件。验证可能会或可能不会在既定的运营环境中执行。
虽然行政令中提到的是“厂商测试 (vendor’s testing)”一词,但含义更宽泛且包括开发者在内。虽然开发者和供应商可能是同一个实体,但很多供应商中包含外部来源的软件。软件供应商可能会对由其它实体开发的软件包进行再次验证。尽管行政令中提到了商业软件,但该指南旨在所有软件开发者包括政府和开源软件开发者应用的软件。本文档中展示的技术和程序可供软件开发者用于验证集成到产品中的复用软件、供客户购买软件、供相关实体接受合同软件使用或供第三方实验室使用。然而,这些群体并非本文档的预期受众,因为这种保证应当尽早在开发进程中应用。
本文档展示的是“最低标准‘,即本文档并非对最有效或最推荐实践的指南,而是为了通过提示开发者应当已经正在使用的技术来设置软件验证的最低门槛,以及是未来制定强制标准的基础。
为确保软件按照开发者意图运行且不受漏洞影响(漏洞是指故意在软件设计的或在生命周期内任意时间不慎插入的漏洞),需要使用很多相互关联的技术。本指南推荐如下开发者测试最低标准:
1、 威胁建模
NIST 建议尽早使用威胁建模,识别设计层安全漏洞并专注于验证。威胁建模方法创建对系统的抽象、潜在攻击者画像如目标和方法以及创建潜在威胁的分类。应当在开发过程中多次进行威胁建模,尤其是在开发新能力过程中,以便捕捉到新威胁并改进建模。威胁建模可提示哪些输入向量最值得注意,对这些特定输入的变体进行测试应当放到更高的优先级。威胁建模可能会披露某少量代码(通常少于100行)具有重大风险。这些代码可能提示手动代码审计回答一些特定问题,如“在应当授权的情况下软件是否要求进行授权”以及“软件接口是否检查且验证输入”等。
2、自动化测试
自动化测试就像在输入上运行程序、捕捉输出并比对输出与预期结果的脚本那样简单;也可以像设置环境、运行测试之后进行检查的工具那样复杂。高阶工具会生成报告说明哪些代码通过测试,或者说明通过模块或子系统的测试次数情况概述。
文档建议开展自动化测试,持续运行测试、准确地检查结果并将对人工和专业知识的需求降到最低。自动化测试可集成到现有的工作流中或发布追踪系统。随着测试的自动化,可经常开展测试比如对每个 commit 或在问题过期前进行测试。
3、基于代码的分析或静态分析
分析通常划分为基于代码的分析或静态分析(如静态应用安全测试SAST,如奇安信代码卫士)和基于执行的分析或动态分析(如动态应用安全测试DAST)。纯粹基于代码的分析独立于程序执行。静态代码扫描工具在对所写代码的推断方式在某种程度上和人工代码审计员无异。
静态分析扫描工具可能解决的问题包括:该软件是否总能满足安全策略要求?它是否满足重要属性?是否存在任意输入使其失败?
NIST 建议使用静态分析工具(如奇安信代码卫士)检查代码中的很多种漏洞,以及检查与组织机构编码标准的合规性。对于多线程或平行处理软件,使用能够检测出竞争条件漏洞的扫描工具。
静态扫描工具的复杂程度不一,比如仅仅检查是否使用了已弃用函数、查找表示可能存在漏洞的模式、能够验证某段代码是否忠实地实现了某通信协议等。应当在代码编写完成后尽快执行静态源代码分析。在大规模的可执行代码完成前,可先检查少量代码。
4、审计硬编码机密
NIST 建议使用启发式工具检查代码中的硬编码密码和私钥。这类工具是可行的,因为将这些作为参数的功能或服务具有特定的接口。动态测试不可能发现这类多余代码。
虽然降低恶意代码的主要方式是完整性措施,但启发式工具可通过识别可疑的少量代码,触发手动测试,协助发现恶意代码。
5、通过编程语言提供的检查和防护措施运行
编译语言和解释性语言提供了很多内置检查和防护措施,在开发过程中和软件交付过程中使用这些能力,也要启用硬件和操作系统安全和漏洞缓解机制。
对于通过内存不安全的编程语言编写的软件,考虑使用执行内存安全的技术。解释性语言通常内置重大安全措施,不过也可以使用额外措施。另外,也可使用静态分析工具检查危险函数、有问题的参数和其它可能的漏洞问题。
即使执行了这些检查,也必须执行程序。执行所有可能的输入是不现实的,除非具有最小输入空间的程序。因此,开发人员必须筛选或构造测试用例。静态代码分析可增强测试用例之间差距的保证,但仍然需要挑选测试执行。
6、黑盒测试用例
“黑盒“测试并非基于实现或特定代码,而是基于功能标准或要求、负面测试、拒绝服务和过载、输入边界分析和输入结合。在通用安全原则认为安全敏感或关键的地方,测试用例应该更加全面。
7、基于代码的测试用例
基于代码的或结构性测试用例基于实现,即代码细节。例如假设软件要求处理最多100万哥项目,程序员可能决定让软件在统计分配的表格中处理100个或更少的项目,但如果出现100多个项目则动态分配内存。对于这种实现,可能会有100个、99个或101个项目以便测试不同方法下的漏洞。内存对齐可能意味着额外测试。无法仅通过标准来确定这些重要的测试用例。基于代码的测试用例可能也源自覆盖矩阵,多数代码应当在单元测试过程中执行,建议执行测试套件实现最低80%的语句覆盖率。
8、历史测试用例
某些测试用例的创建就是为了显示漏洞的存在或消失,有时被称作“回归测试“。这些测试在早期是重要的测试来源,在”第一原则“保证方法出现之前应该检测到bug。更好的方法是使用保证方法如选择语言来完全排除 bug。从生产操作记录的输入可能也是测试用例的良好来源。
9、模糊测试
NIST 建议使用模糊测试工具执行自动化的主动测试,即模糊测试工具在测试过程中创建海量输入。通常很小的输入部分就会触发代码问题。另外,这些工具仅执行一般检查来判断软件正确地处理了测试。一般而言仅会监控宽泛的输出特征和恶意行为如应用崩溃。一般化的优势在于这些工具可通过最少的人工监控来尝试庞大的输入。这些工具可通过通常暴露 bug 的输入(如非常长或空的输入和特殊字符)进行编程。
10、Web 应用扫描
如果软件提供了web服务,则使用动态应用安全测试或交互应用安全测试工具。和模糊测试工具一样,web app 扫描工具在运行时创建输入。Web app 扫描工具监控一般的异常行为。混合工具或 IAST 工具可能也会监控程序执行中的内部错误。当输入引发某些可检测的异常情况,则工具可使用输入变体来检测失败情况。
11、检查所包含的软件组件
使用以上提到的验证技术保证所包含的代码起码和本地开发的代码一样安全。某些保证可能源于自认证或部分自认证信息如核心基础设施倡议 (CII) 最佳实践徽章或可信任的第三方检查。
必须持续监控软件组件中的已知漏洞数据库,可能随时会报告现有代码中的新漏洞。
软件成分分析工具(如奇安信开源卫士)或源分析工具助于识别软件使用了哪些开源库、套件、程序包、绑定、包等。这些工具有助于判断软件的实际导入、找到被复用的软件(包括开源软件)并知会过期或含有已知漏洞的软件。
NIST 按行政令关于加强软件供应链安全的要求,给出“关键软件”的定义及所含11类软件
美国 CISA 和 NIST 联合发布软件供应链攻击相关风险及缓解措施
https://www.nist.gov/system/files/documents/2021/07/13/Developer%20Verification%20of%20Software.pdf
题图:Pixabay License
本文由奇安信编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的产品线。