NIST IR 8151: 显著减少软件漏洞——致美国白宫科技政策办公室

NIST 跨部门报告 8151

显著减少软件漏洞——致美国白宫科技政策办公室

Paul E. Black,Lee Badger,Barbara Guttman 和 Elizabeth Fong 著

信息科技实验室

此出版物可从此处免费获得:

https://doi.org/10.6028/NIST.IR.8151

2016 年十一月

美国商务部 秘书 Penny Pritzker

美国国家标准技术研究所 标准技术商务次长兼主任 Willie May

美国国家标准技术研究所跨部门报告 8151,64 页(2016 年十一月)

此文档中可能会提到某些商业实体、设备或者器材以便充分地描述某种试验程序或者概念。这样的提名的本意并非暗示 NIST 对其的推荐或认可,也非暗示这些实体、器材或者设备一定是可用于该目的之最好的。

此文档中可能会有对于 NIST 的当前正在开发中的其他出版物的引用,以便符合其被赋予的法定责任。此出版物中的信息,包括概念和方法论,可以被联邦政府机构使用,即使是在这些附带的出版物完成之前。因此,直到每部出版物完成之前,当前的要求、指导意见和过程在其所存在之处仍然有效。关于计划和迁移的目的,联邦政府机构可能想要紧密跟踪由 NIST 提供的这些新出版物的进展。

我们鼓励组织机构在公开评论期间审阅所有出版物草案,并且向 NIST 提供反馈。除了上述出版物以外,NIST 的众多计算机安全出版物可以从 https://csrc.nist.gov/publications 获取。

关于此出版物的评论可以被提交至:

美国国家标准技术研究所

收件人:计算机安全分部,信息科技实验室,办事处大道 100 号(8930 邮递点),盖瑟斯堡,马里兰州 20899-8930

邮件:[email protected]

所有评论必须在美国信息自由法(FOIA)条款下发布。

摘要

对于显著减少软件漏洞的诉求发出自众多来源,从最近的 2016 年二月发布的美国联邦网络安全研发战略计划开始。此计划以描述众所周知的危险性开始:当前的系统正在执行着越来越关键的任务,并且其存在漏洞这一点广为人知。这些漏洞通常不易发现并且难于修复。网络安全并未跟上步伐,并且所需的步伐正在快速加速。此报告的目的是呈现一系列特定的技术方式,它们拥有在减少漏洞方面发挥显著作用的潜力——通过在漏洞发生之前阻止它们、在漏洞被利用之前发现它们,或者降低漏洞所造成的影响。

关键字

测定;度量;软件担保;软件措施;安全漏洞;减少软件漏洞

致谢

非常感谢 Rajeev Joshi([email protected]),由于其对第 2.3 节“附加软件分析技术”的贡献。

同样感谢来自麻省理工学院林肯实验室的答辩、研究和工程助理秘书办公室的合同官 W. Konrad Vesey([email protected]),由于其为第 2.5 节“移动目标防御(MTD)”和“自动软件多样性”提供的素材,大量词句直接来自作者同他的私人通讯。

我们感谢 Terry Cohen、Mark Cornwell、John Diamant、Jeremy Epstein、D. Richard Kuhn、Andrew Murren、Kenneth S. Thompson、Jan Vandenbos、David Wheeler 和 Lok Yan,由于他们的大量评论和建议极大地改进了此报告,我们还要感谢众多提出了改进意见、提问了问题并且提交了评论的其他人。

第 1 章 简介

对于显著减少软件漏洞的诉求正在发出自众多来源,包括 2016 年二月发布的美国联邦网络安全研发战略计划 [FCRDSP16]。此计划以描述众所周知的危险性开始:当前的系统正在执行着越来越关键的任务,并且其存在漏洞这一点广为人知。这些漏洞通常不易发现并且难于修复。网络安全并未跟上步伐,并且所需的步伐正在快速加速。此计划定义了近期、中期和长期的目标。此报告解决的是首个中期目标:

取得 S&T [科技] 进展以逆转对手的非对称优势,通过开发和运行具有可持续的安全性的系统……这一目标是双管齐下的:首先是对于恶意网络活动(例如普遍存在的软件缺陷所引起的众多漏洞)具有高度抵抗力的软件、固件和硬件的设计和实现……

“漏洞”一词具有众多不同的定义,它们覆盖了不同的概念的组合,包括知识、攻击、可利用性、风险、意图、威胁、范围,以及引入的时间等。出于此报告的目的,我们将 漏洞 定义为可以被无意或者有意利用,并且导致对于理想的系统属性的侵犯的一个或者更多弱点。弱点是指系统的要求、设计或者实现中的不理想的特性 [Black11a]。这一定义排除了:

  • 手动配置或者操作的错误,诸如将某个程序安装为世界可读取,或者为管理员访问设置平凡的口令
  • 局中人的不法行为,诸如 Edward Snowden 的秘密潜出
  • 功能 bug,诸如混淆 SI(国际单位制)和英制单位,这导致了 1999 年的火星气候探测者号失事 [Oberg99]
  • 在常规代码中故意引入的恶意软件或者导致损坏的“不良特性”,诸如允许 root 访问,如果用户名是“JoshuaCaleb”,以及
  • 作为输入过滤或者其他化解措施的结果而不能(由“局外人”)利用的软件弱点

在定义软件漏洞,对其进行分类并且理解它们等方面已经实现了重大跨越。此外,在对软件社区进行关于漏洞、相关的补丁以及底层的弱点的教育中也已经实现了重大跨越。然而,此作品是不充分的。大量漏洞被程式化地发现,众多漏洞多年以来未被发现,并且补丁经常未被应用。很明显,一种不同的方式——依赖于改进软件的方式——是必需的。

强化保护要求增加这样的担保,即人们所开发和部署的产品对于恶意网络活动具有高度抵抗力,由于它们只包含极少的漏洞…… [FCRDSP16, p. 17]

1.1 报告的范围

此报告的目的是呈现一系列特定的技术方式,它们拥有在减少漏洞方面发挥显著作用的潜力——通过在漏洞发生之前阻止它们、在漏洞被利用之前发现它们,或者降低漏洞所造成的影响。

  • “在漏洞发生之前阻止它们”通常包括用于具体说明、设计和构建软件的改进方法
  • “发现漏洞”包括更好的测试技术以及对于多种测试方法的更有效的利用
  • “降低漏洞的影响”指的是用于构建更具弹性的架构的技术,以使得漏洞不能被用于造成重大伤害

此报告并未将这些方法分割为 3 块,由于某些方法可能包括来自多个方面的内容。此报告中的方法列表并不完备,它们的本意是为了展示范围宽泛的方法是如何能够产生某种重大影响的。新的方法将会持续被开发出来并且投入一般应用。

用于减少漏洞的方法列表专注于满足以下 3 个判据的方法:

  1. 显著的影响
  2. 3~7 年的时间框架,以及
  3. 技术活动

显著:这意味着这些方法广泛适用并且能够为将漏洞减少两个数量级这一目标作出重大贡献。在常规软件的情况下,这一数值的估计高达每 1000 行代码中包含 25 处错误 [McConnell04, p. 521]。将近 2/3 的漏洞来源于简单的编程错误 [Heffley04]。这些方法被选择以实现这样一种可能性,即增强将此类软件代码控制在每 100000 行包含 25 个错误以内这一雄心壮志,并且实现其他类别的软件中的相应的错误减少率。(在当今的航空航天行业,接近零错误的系统被程式化地制造出来,但是其成本数倍于常规软件。)要想确定某种方式是否能够带来显著的影响,需要有能力以测定它。测定软件质量是一项困难的任务。关于改进软件漏洞测定方法的并行努力正在进行中。

3~7 年的时间框架:之所以选择这一时间框架,是由于它足够长远,以允许作出显著改变,基于那些并未达到实现其影响的全部潜力的程度的现存技术。这是一个可以合理地思考的时间框架。如果超过了这一时间框架,要想预测哪些新技术将会被开发出来,并且潜在地对于信息科技将会被如何使用这一点作出其自身的一套显著的改变,这件事过于困难。在不远的未来,强调的重点将会是实施那些已经部署的技术,诸如在安全的软件开发和测试中的工作。已经部署的技术和未来的技术之间的分界线并不脆弱。如果某项技术被广泛应用,或者被主要的软件开发者所使用,它并未被包括进来,尽管此技术的更加广泛的采用将会是有益的。

技术性:有众多不同类型的方式以减少软件漏洞,它们中的很多主要来说并非技术性的——从帮助用户有意义地请求得到安全性,到资助研究和运行活动以及训练设计、构建、测试和使用软件的所有这些相关方。在此报告的开发过程中,很多理念被推进到这步阔步跨越以外。此报告只是应对了技术性的方法,以获得可管理的范围,这一范围构建于开发此报告期间的可用专业技能之上。这些其他领域也很重要。

在此报告的草案阶段,众多不在此报告的范围之内的优秀想法被提了出来,并且在第 4 章总结出来。这些活动的范例包括:

  • 改进的资助
  • 改进教育
  • 对于对软件的理解的不同方面的更多研究
  • 对于大规模挑战和竞争的增加利用
  • 为软件消费者提供更好的方法以对低漏洞的软件进行请求和评估
  • 责任和标准,以及
  • 威胁分析

此报告排除了一段关于硬件漏洞的讨论。这并不是说它并不重要。这些内容可以在另一篇报告中解决。此报告针对范围宽泛的软件,包括政府合同软件、私有和开源软件。它覆盖了用于通用目的、移动设备以及嵌入在家电和设备中的软件。其目的是防止新代码中的漏洞,以及识别并修补现存代码中的漏洞。

1.2 发现

尽管减少软件漏洞是一个困难的问题,并且很明显地需要技术、操作、管理、心理和文化等方面的改变相配合才能解决此问题,想要引起显著的改变仍然是可能的。此报告描述了 5 种中期方法,它们拥有潜力以解决此问题的技术方面。此处所包括的方式并非一个完整的列表;它们代表了范围宽泛的潜在方法,并且强调了减少软件漏洞可以如何实现。所有这些方法将会要求改进的研究基础设施,包括显著改良的度量方法。如同注释的那样,它们就其自身而言不能取得成功,并且需要被整合到更大的软件开发者和用户社区之中。更进一步地,此报告并不专注于已经投入大规模使用的安全的软件开发的当前趋势。

1.3 受众

此报告的主要受众是美国白宫科技政策办公室(OSTP)。可以预期的是,其他政策实体、资金提供者和研究人员也会发现此报告有用,由于他们将会考虑投资和项目以改进软件质量。由于此报告专注于 3~7 年的时间框架,它的本意并非作为软件开发者的指南。

1.4 措施

有多种努力以定义软件漏洞、它们的流行度、它们的可检测性,以及检测和化解技术的效率。测定软件的能力可以在显著减少软件漏洞中发挥重要作用。业界要求关于这样的漏洞的严重程度的证据,以及关于确定哪些技术对于开发具有显著减少的漏洞的软件最为有效的知识。有了可以发挥市场信号作用的有效措施,业界就可以倾向于并且选择低漏洞的软件,并且因此鼓励更好的软件的开发 [Grigg08]。更进一步地,以及更加关键的是,业界要求关于识别在代码中部署化解措施或者其他行为的最佳位置的指导。这些证据来自于在最宽泛的意义上测定或者评估软件的属性。

1.5 方法论

为了编纂这些方法的列表,科技政策办公室(OSTP)请求 NIST 领导一支基于社区的力量。此报告的开发历时 8 个月,鉴于时间框架的压缩,此报告的关注焦点被限制为上述判据,以强调出有前途的方法,而非进行一整套分析。NIST 咨询了来自下列软件担保社区的多位专家:

  • 两次由 OSTP 组织的跨部门圆桌会议
  • 软件和供应链担保(SSCA)夏季论坛中的半天时间的议程
  • 关于减少安全漏洞的软件措施和度量的全天研讨会
  • 关于减少软件缺陷和漏洞的两天时间的研讨会,此研讨会由网络和信息科技研发(NITRD)计划中的软件生产力、可持续性和质量(SPSQ)工作组组织,以及
  • 2016 年十月 4~18 日的公开评论

1.6 报告的组织

此报告被组织为两个主要章节。第一个主要章节是第 2 章,它枚举了技术方法,以及第二个主要章节,第 3 章,它解决了相关措施。

第 2 章分为关于应对软件中的漏洞的各个技术方法的小节。这些小节包括形式化方法,诸如可靠的静态程序分析、模型检查器以及布尔可满足性问题(SAT)求解器。它还建议拥有经过验证的工具和代码的目录。这一章解决了系统层级的安全性,包括操作系统容器和微服务。附加软件分析技术也得到了解决。最后,它讨论了移动目标防御(MTD)和自动软件多样性。这些包括编译时技术、系统或者网络技术,以及操作系统技术。

每个小节遵循相同的格式:

  • 定义和背景:对此领域及其背景的定义
  • 成熟度级别:此领域有多么成熟,包括关于此方法已经被应用于“真实世界”还是仅存于实验室中的讨论,以及与可放大性和可用性相关联的话题
  • 可信度的基础:关于为何此方法能够发挥作用的理论基础
  • 潜在影响的理论基础,以及
  • 延伸阅读,包括论文和其他素材

第 3 章覆盖了软件措施,它被设计为鼓励采用测定和工具以解决软件中的漏洞。它解决了产品措施以及如何开发更好的代码。它也解决了关于软件安全性和质量措施的关键性的问题。

在这两个主要章节之后是第 4 章,关于跨领域的问题,诸如雇佣研究社区、教育以及载体以使得这些技术方法能够转化为一般应用,以及第 5 章中的参考文献。

第 2 章 技术方法

有众多具有不同成熟度等级的方法展现出了对于减少软件漏洞数量的巨大潜力。此报告突出强调了其中 5 种足够成熟并且被证明为成功的方法,因此有可能将其外推到 3~7 年的视界中来。此列表的本意并非穷尽性,而是为了展示在减少漏洞方面取得显著进展是可能的,并且为了取得这一充满雄心壮志的目标铺平道路。SPSQ 研讨会的重要主题之一是这样一种需求,即不仅仅要改进软件,还要通过应用形式化技术来改进测试工具。

2.1 形式化方法

形式化方法包括基于数学和逻辑的所有软件分析方法,包括语法检查、类型检查、正确性证明、基于模型的开发,以及自动建构校正等。形式化方法可以帮助软件开发者取得关于整个类别的漏洞都不存在的更大的担保,并且还可能有助于减少不可预测的昂贵的测试和 bug 修复周期。

在编程的早期,某些实践者证明了他们的程序的正确性,即给定语言语义,他们从逻辑上证明了他们的程序具有某些属性或者能够得到某些结果。随着软件的应用爆炸式增长,以及程序变得如此之大,以至于单纯的手动证明变得不可行。形式化正确性参数不再流行。近几十年的发展,诸如由摩尔定律预测到的处理能力的激动人心的增长、多核处理器以及云计算,使得随时可用的计算性能增加了好几个数量级。用于求解布尔可满足性(SAT)问题、可满足性模数理论(SMT)[Bjørner16]、决策过程(例如有序二元决策图——OBDD)以及推理模型(例如抽象的解读和分离逻辑)等问题的算法的进展极大地削减了回答这些关于软件的问题所必需的资源。

关于使用形式化方法以实现大幅减少漏洞的早期努力之一是 20 世纪 80 年代美国国防部的可信计算机安全性评估判据(TCSEC)。TCSEC 详细叙述了多个层级的软件担保。其最高层级 A1 要求对于系统的形式化说明以及对于代码和说明之间的相关性的数学证明。成功的定理证明工具被开发出来,并且若干种经过形式化证明的系统被制造出来,但是实际使用所必需的代价和时间令人难以接受——多达 2 年。

到了 20 世纪 90 年代,形式化方法得到了这样的名声,即消耗太长太长的时间,不论是机时、人年还是项目时间,并且需要计算机科学的博士学位,还要懂得数学才能利用它们。现在的情况已经不尽如此。今天,形式化方法被普遍使用。例如,编译器利用 SAT 求解器以分配寄存器并且优化代码。操作系统利用形式化保证的算法以避免死锁。Kiniry 和 Zimmerman 称这些为“隐秘忍者式的形式化方法”[Kiniry08]:它们对于用户不可见,除非是报告某些东西不正确。与这些“不可见”的形式化方法的使用相反的是,显式的使用通常要求将问题重新呈现为某种与形式化方法工具兼容的形式。

显式形式化方法在机动车 [ISO26262-6] 和铁路 [Boulanger15] 标准中被推荐。形式化证明技术显著减少了取得由空运标准 DO 178B 所定义的目标所需付出的努力 [Randimbivololona99]。其继任者 DO 178C 拥有一整套补充:DO 333,它专门针对将形式化方法用于软件验证。大多数被提议的密码学协议现在经过模型检查器检查以查找可能被利用的漏洞,并且分析者可以执行实现了密码学算法匹配规范的几乎完全自动化证明 [Carter13]。实践者们还利用模型检查器以查找网络中的攻击路径。

抛开它们的长处,如果对于软件要求没有明确的声明,或者到底是哪些东西构成了恰当的软件行为这一点只能通过人类判断或者平衡众多相互冲突的因素来确定,则形式化方法不那么有效。因此,我们将不会期待形式化方法对于评估用户界面的可用性、部署探索性的软件,或者非结构化的问题作出那么大的贡献。

形式化方法包括软件开发的所有阶段以及众多不同应用领域的众多技术,我们不能列出每一种潜在地有帮助的形式化方法。与之相反,我们专注于可能在中期作出显著贡献的少数方法。

2.1.1 可靠的静态程序分析

静态分析是在不执行软件的情况下对其特定属性进行检查的过程。出于我们的目的,我们只考虑自动化的分析。启发式分析比可靠性分析更快,但是缺少来自于逻辑推理链的担保。有些问题只能通过在分析的条件下运行软件,即通过动态分析来回答。结合静态和动态分析将会得到一种混合技术。特别地,通过执行软件可以得到关于那些不能仅仅利用静态技术来确认的属性的存在性证明。

软件的众多呈现形式(例如系统要求、架构、源代码和可执行文件)可以进行静态分析。然而,源代码分析是最成熟的。源代码分析的优势之一在于,在源代码中识别出来的问题的上下文可以通过熟悉的呈现形式传递给软件开发者:代码本身。如果其他呈现形式被分析,则需要额外的步骤以将报警信息转化为某种形式,人们可以首先理解它,并且随后将其与分析中的程序相关联。

根据 Doyle 的评估,可靠的静态分析在覆盖度、可缩放性和付出努力的回报等方面均优于当前的软件开发实践 [Doyle16]。我们相信其限制之一是某些属性难于通过可用的概念来叙述。

形式化描述和可靠的静态分析在近年来已经展示出显著的适用性。例如,Tokeneer 项目展示了利用形式化方法开发软件比传统软件开发技术更快、更廉价,并且具有更少的 bug [Barnes06, Woodcock10]。TrustInSoft 利用 Frama-C 以证明 PolarSSL 中不存在一系列通用缺陷列表(CWE)中的类,它现在称为 mbed TLS [Bakker14, Regehr15]。Ourghanlian 比较了 PolySpace 验证器、Frama-C 和 Astrée 的应用以评估核电站中的安全关键软件 [Ourghanlian14]。可靠的静态分析和其他形式化方法被广泛应用于不限于交通运输、航空航天、核电站控制等领域的软件开发 [Voas16b]。

这些进展体现出了静态分析的众多应用中的少数。更进一步,静态分析拥有这样的潜力以有效地排除新开发的软件中的若干类错误,并且减少与通过测试达到更高层级的担保所需资源相关的不确定度。

2.1.2 模型检查器、SAT 求解器和其他“轻量级”决策算法

这些算法可以解答关于理想的更高层级属性的问题,诸如某个协议仅在某人拥有某个密钥的情况下允许读取敏感文本、安全属性由系统预留、某项赋值满足多个限制条件,或是没有途径通过(已知的)攻击进行突破。这些算法也可以被应用于分析具体的设计产物,诸如有限(以及无限)状态机。

Doyle 的评估结论是,模型检查器可能拥有优异的覆盖度,很多属性可以被呈现 [Doyle16]。然而,由于所需的努力随着问题大小呈指数增加,总会有某个事实上的大小限制。小于该限制的问题可以被快速求解。非常大型的问题可能要求额外的资源或者密集的人力以便将此问题分解为合理的部分。

这样的技术实质上可以通过两种方式应用。其一,它们可以被用作生产中的软件的一部分。例如,与其使用某种临时安排的程式以便为一台运输卡车查找一条高效的路径,某个应用程序不如使用已有深入研究的旅行推销员或者生成树算法。其二,可能也是与此报告的主题更加相关的方式是使用这些方法来设计或者验证软件。

2.1.3 断言、先决条件、后置条件、不变量、切面和契约

程序员通常拥有一个信息体以为其提供关于软件将会按照预期执行的信心。形式化方法中的一个被忽略的部分是无歧义地记录这些洞察力。变量拥有不同的术语,诸如契约、断言、先决条件、注释、后置条件和不变量等。这可能会使得程序员花费额外的思考以使用某种类似于代码表达式的语言来精确地叙述将会发生什么,但是这样地声明是会带来帮助的。诸如由反例指导的抽象详细化(CEGAR)等自动化辅助工具可以帮助生成声明。这些声明在开发和测试过程中被激活(“编译进来”),然后可以在发布之前取消激活。

这种方式的好处是,关于代码中具有的属性的形式化声明可以被用于对代码进行交叉检查。例如,测试可以通过断言直接生成。它们可以被激活以便在测试或者生产过程中执行内部一致性检查。由此可以使得错误被检测出来的时间大大提前,并且距离出错的代码更近,而非不得不从外部可见的系统故障进行回溯。基于断言的测试可以检测出具有适当的覆盖度水平的输入空间中的多达 90% 的错误 [duBousquet04]。这样的声明还提供了额外的信息以执行关于程序正确性的半自动的证明。与在代码更改时不会被更新的注释不同的是,这些声明可以被计算机证实或者强制实施,并且因此必须持续成为关于程序特性和属性的准确声明。

关于这样的形式化声明可以如何带来帮助的一个令人印象深刻的例子是 1996 年的阿丽亚娜-5 运载火箭首次发射失败。阿丽亚娜-5 使用了来自取得成功的阿丽亚娜-4 的软件。当阿丽亚娜-4 被设计之时,分析显示 16 位整数能够处理其速度。然而,阿丽亚娜-5 的更高的速度使得该变量溢出,导致计算机关机以及运载火箭失事。如果其代码拥有关于其速度必须能够适配进 16 位整数的先决条件,“任何称职的团队将会检查……[此先决条件,它] 将会立即提示阿丽亚娜-5 的调用软件并不满足它所调用的阿丽亚娜-4 例程的预期” [Jézéquel97]。

2.1.4 自动建构校正和基于模型的开发

在基于模型的开发中,软件开发者创建并且修改系统的模型。其行为可以在某种更高级或者领域特定的语言或者模型中说明,随后其代码被自动生成。大部分或者全部代码是从模型生成的。这是一种自动建构校正技术。此技术和诸如详细化设计等其他技术致力于完全避免整类漏洞,由于开发者极少接触代码。与此类似的代码合成相对于其他形式化方法适用于较少的情况,由于这对于为某些领域开发建模超结构和代码生成器是不可行的,例如,某种具有错误恢复和帮助提示的用户界面。这样的模型或者规范还可以生成测试套件或者准则。它们还可以被用于验证或者监视系统运行。

如果分析者能够指定整个系统,或者哪怕只是子系统的完整的高层级模型,我们就称此模型为“领域特定语言”(DSL),并且不再认为它值得一提。这代表了形式化方法的一种实质性的应用。根据 Doyle 的评估,程序合成在覆盖度方面等级为“A+”,而在努力和属性方面等级为“B”[Doyle16]。

2.1.5 经过验证的工具和代码目录

软件开发者通常必须花费大量努力以便将具有已证明的属性的工具或者开发程序认定为合格。即使如果后期的开发者想要使用这样的工作成果,也没有中央结算机构可供咨询。关于经过验证的工具、精心构建的库,甚至是可重复使用的规范和要求都能够加速形式化方法的采用。这样的工具库可能有助于具有显著减少的漏洞数量的软件的更宽泛使用,并且具有随之而来的担保。

众多企业和政府机构评估用于类似用途的相同的工具或者软件。由于可能难以发现谁已经完成了相关评估,每一家实体都必须重复此工作,有时它们的知识和细致程度还不如其他实体已经投入的。这特别具有挑战性,由于众多合同条款阻碍分享成果 [Klass16]。一份库或者列表将会带来巨大利好。一旦得知相关的努力成果,开发者可以为一项努力成果作出贡献,而非从事他们自己的努力。作为某个库的代码或者“即时”实例化成果,开放式网络应用程序安全计划(OWASP)基金会协调组织了一个项目以开发一个囊括了关键安全性操作的应用程序接口(API),它称为企业安全性 API(ESAPI)。

参见 2.4 节以获得关于经过良好测试和良好分析的代码的重复利用的讨论。

2.1.6 网络加固:使形式化方法发挥作用

上述技术可以被用于开发软件,然而,重制所有遗产软件是不可行的。这被称为“网络加固”,以同旨在获得对于地震的更高抵抗力的“抗震加固”相类比 [Fisher16]。第一步是识别现存系统中最具决定性、关键性或是基础性的组件。SPSQ 研讨会参与者还强调了将形式化方法用于关键模块而非整个应用程序。除了基于目的编写的代码以外,关键组件还可以是编译器或者运行时库。这些组件随后利用适当的形式化方法仔细检查或者重建以获得更高层级的担保,如同在 PolarSSL 中所进行的,它现在称为 mbed TLS [Bakker14, Regehr15],继 Heartbleed 或者 CompCert 验证 C 编译器之后 [Leroy06]。

网络加固中的另一个小步骤是在具有自动强化或者加固的情况下重新编译组件。例如,编译器可以在每当可能时对所有的内存访问添加边界检查,以极大地减少未被识别的缓冲区溢出(BOF 类)的数量 [Bojanova16]。这样的强化几乎没有任何性能影响 [Flater15]。编译器还可以利用更为安全的“加强”函数来替换典型的不安全函数,并且可以利用可执行空间保护,例如将用于数据的内存区域标记为不可执行。

2.1.7 成熟度水平

今天,形式化方法在全世界被使用,通常是相对地隐秘的。最为普遍的应用之一是现代编程语言中的强类型检查,这是一种形式化方法。其他尽管有限的应用包括不同软件检查工具的算法,它们中的某些被构建到广泛使用的开发环境中(例如标记出对变量的不一致使用、缺失的值或者不安全接口的使用)。在 2010 年,澳大利亚国家信息通讯科技卓越研究中心(NICTA)的研究人员展示了对于包含约 10000 行 C 代码的 seL4 微内核的形式化验证 [Klein14]。英国国家航空交通服务控股公司(NATS)的临时未来领域控制工具支持(iFACTS)包含超过 200000 行 SPARK 代码,并且“所有代码更改 必须 被证实为良好,然后代码才能被提交”[Chapman14]。

2.1.8 可信度的基础

断言、契约、不变量以及其他形式化声明在高质量软件中已经得到大量采用。它们之所以得到逐渐改进以涵盖更多高级条件和 API 检查,是由于它们已经在开发者社区中证明了自己的价值。例如,源代码注释语言(SAL 2.0)在微软 Visual Studio 2015 中可用。众多工具现在可以执行静态分析。一种自然的发展趋势是不断提升更多高级形式的静态和混合分析。基于诸如先决条件和后置条件的满足性以及随码证明等技术的软件证明已经在关键软件中开始得到采用 [Souyris09]。它们要求更多的努力和成本,然而,在某些案例中,它们被证明为在长期具有成本高效性:在 1/3 的应用中具有开发时间和成本方面的改进,而对于已部署的系统只需较少的修补甚至不需要修补 [Woodcock09]。

2.1.9 潜在影响的基本原理

最大的潜在影响可能在于避免了那些随着时间演进会被严重依赖的组件的成本。Heartbleed 漏洞是一个例子,关于较小的代码基具有过大的重要性:对于形式化方法的明智使用可能会在一上来就避免此问题。通常,诸如那些可以利用形式化方法制造的高质量软件可以被用于降低软件组件的长期维护和替换成本。不像物理系统那样发生磨损并且最终失效,软件系统只会在它们本身不正确,并且其瑕疵被诸如特定的输入序列或者组合等环境因素触发时才会失效 [Woody14]。

2.1.10 延伸阅读

  • [Armstrong14] Robert C. Armstrong, Ratish J. Punnoose, Matthew H. Wong and Jackson R. Mayo, “Survey of Existing Tools for Formal Verification,” Sandia National Laboratories Report SAND2014-20533, December 2014. Available: http://prod.sandia.gov/techlib/access-control.cgi/2014/1420533.pdf Accessed 12 October 2016.
  • [Chapman14] Roderick Chapman and Florian Schanda, “Are We There Yet? 20 Years of Industrial Theorem Proving with SPARK,” in Proc. Interactive Theorem Proving: 5th International Conference, ITP 2014, Held as Part of the Vienna Summer of Logic, VSL 2014, Vienna, Austria, July 14-17, 2014. Gerwin Klein and Ruben Gamboa, Eds., Lecture Notes in Computer Science, Vol. 8558, Springer, 2014, pp. 17-26, https://doi.org/10.1007/978-3-319-08970-6_2.
  • [Voas16a] Jeffrey Voas and Kim Schaffer, “Insights on Formal Methods in Cybersecurity,” IEEE Computer, Vol. 49, Issue 5, May 2016, pp. 102–105, https://doi.org/10.1109/MC.2016.131. 7 位形式化方法专家的立场.
  • [Voas16b] Jeffrey Voas and Kim Schaffer, “What Happened to Formal Methods for Security?”, IEEE Computer, Vol. 49, Issue 8, August 2016, pp. 70-79, https://doi.org/10.1109/MC.2016.228. 同上述 7 位专家的关于形式化方法的后续圆桌会议.
  • [Woodcock09] Jim Woodcock, Peter Gorm Larsen, Juan Bicarregui and John Fitzgerald, “Formal Methods: Practice and Experience,” ACM Computing Surveys, Vol. 41, Issue 4, October 2009, pp. 1-36, https://doi.org/10.1145/1592434.1592436.

2.2 系统层级的安全性

当软件被执行时,用于该运行着的软件的系统上下文定义了可用于该软件的资源、访问这些资源所需的 API,以及软件可以如何访问外部实体(以及被它们访问)。系统上下文的这些方面可能会强烈影响以下内容:软件包含漏洞的可能性(例如复杂或者有 bug 的 API 将会增加这种可能性)、攻击者利用漏洞的可能性(例如系统服务越容易从外部接触,这种可能性就越大),以及攻击可能具有的影响(例如,对于系统资源和具体任务成本的损害)。

长期以来,系统设计者的目标之一是设计出对于攻击具有抵抗力,并且对于程序和用户都能强制实施理想的安全策略的系统。自 1965 年开始的多任务信息与计算系统(Multics)[Corbato65] 结合了若干种理念(例如虚拟内存、多进程和内存段等)以实现一种计算工具,它能够保护信息以防止非授权访问。自 20 世纪 70 年代开始,若干种安全策略模型被引入以使得系统层级的安全责任形式化。在 1976 年,Bell-LaPadula(BLP)模型 [Bell76] 提供了关于保护分级信息的强制安全性的形式化表达:BLP 模型允许“高”(例如 SECRET(机密))进程访问“低”(例如 UNCLASSIFIED(未分级))信息以获得可用性,但是禁止“低”进程访问“高”信息。 Goguen 和 Meseguer 的无干扰模型解释了间接信息流,又称为隐秘信道 [Goguen84]。Biba 的完整性模型表述了关于完整性的强制安全性:它禁止可能是恶意(低完整性)的数据被高完整性的进程观察到,由此降低高完整性的进程和数据可能发生损坏的风险 [Biba71]。Boebert 和 Kain 的类型强制模型提供了一种基于表格的访问控制机制,它只允许数据被预先批准的程序转换 [Boebert85]。这些模型为理想的安全属性提供了必要的明确性,但是,在真实尺度的系统中使用这些模型为系统管理员带来了可用性的问题,并且这些模型的软件实现仍然包含可被利用的瑕疵。

在 1999 年,美国国防高级研究计划局(DARPA)启动了建立在这一理念之上的入侵容忍系统(ITS)项目,即系统可以被构建为能够继续运作,或者“容忍”哪怕是成功的攻击。随之而来的若干其他研究项目也基于此理念而构建 [Tolerant07]。由这些项目探索的基本概念包括具有冗余和多样化的组件的系统构造,它们不太可能被单一漏洞全部破坏、新的策略强制执行软件层的引入,以及用于自动恢复的诊断推理组件的应用。深入容错系统的 DARPA 研究意识到,从真实世界的系统中消除所有漏洞对于可预见的将来是不太可能实现的。这些研究展示了在红队测试中的实质性容忍(例如参见 [Chong05]),但是这些方法同样施加了显著的配置复杂度、降低的执行速度和显著增加的资源(CPU、内存等)要求。

最近的软硬件进展带来了这样的可能性,即开发出对于性能和成本都很高效的安全性强制执行和入侵容忍系统。这样的系统拥有抑制软件漏洞所能造成的危害的潜力。在硬件方面,低成本的多核处理器和系统芯片正在降低实现冗余度的成本。在与之互补的软件方面,新兴的架构结构正在带来新的机会以便将安全性和容错性构建到下一代系统中。在众多可能的结构中,两种看起来有前途的结构是操作系统容器和微服务。

2.2.1 操作系统容器

“容器是为了运行于其中的应用程序或者系统而隔离宿主的某些资源的对象。”[LXC] 从实质上讲,容器是一个非常轻量级的虚拟机,其资源(内存、硬盘和网络等)可以同宿主计算机或者其他容器进行非常灵活的共享。容器提供了独立计算机或者完整的虚拟机的某些隔离属性,但是,容器可以在商品级硬件上在几分之一秒的时间内启动。容器通常要求显著少于完整虚拟机的计算和存储资源。

基于容器的隔离可以明显减少软件漏洞的影响,如果隔离足够强。因此,获取关于容器基础设施组件(例如 Linux 内核中的控制组和名称空间)在面对恶意输入时是强壮的这一点的担保至关重要。容器用户需要对这些组件进行建模、分析、测试和验证以构建关于容器配置能够按照预期运作的担保。

尽管容器可以非常轻量和灵活,这种灵活性的代价是容器配置的复杂性,这决定了容器中的众多关键元素,诸如它如何共享其资源、它的网络栈如何配置、它的初始进程、它所能够使用的系统调用等等。尽管市场已经接受了支持共享容器配置的管理系统,诸如 Docker [Docker16],仍然需要这样的工具和技术,它们可以分析容器配置并且确定它们能够在多大程度上降低安全风险,包括能够在多大程度上化解软件漏洞的效果。

此外,容器带来了机会以应用某些传统安全性模型以及入侵容忍技术,利用有利于效率和部署的简易度的构建块。现在有了新的机会以重新评估哪些高级安全性模型和入侵容忍技术能够成为主流技术。

更进一步地,由于容器可以围绕某个程序的单次运行而有效地封包起来,容器可以被配置为仅仅授予某个程序对资源的最小访问级别,并且由此遵守最小权限原则 [Saltzer75]。最小权限原则是关于限制软件漏洞和攻击的效果的基本原则。然而,想要具体说明某个程序所要求的最小资源这一点是众所周知地困难的。与其试图在其完整的普遍性之中求解该问题,不如采用某种策略以开发分析技术和工具,以便生成自定义的容器配置,该配置能够近似重要程序类别的最小权限。由于部署容器的相对简易性,这样的工具辅助容器能够为主流系统带来显著增加的访问控制有效性和安全性。

2.2.2 微服务

微服务描述了“一种将软件作为一套小型服务来设计的方式,每个服务运行于其自身的进程之中,并且通过轻量级的机制进行通讯。”[Fowler14] 核心的微服务理念并非最新的:它已经被人们利用网络服务以及在基于微内核的操作系统中探索过了。这些方法包括 Mach 微内核 [Rashid86]、GNU Hurd [Hurd16],以及网络服务架构 [WSA04]。然而,微服务方法根据不同的判据来构造服务。微服务应该实现单个业务(或者任务)能力、拥有独立的刷新循环、替换起来相对简单,并且对于编程语言不可知 [Fowler14]。简而言之,每一个微服务都应该具有其自身的经济和管理意义。与此同时,微服务可能彼此依赖,这可以支持具有良好定义的模块性。

这种系统结构方式可能产生若干组件,其接口被显式定义,并且其依赖也被类似地显式定义。

随着系统运行以及控制流在微服务之间传递,有一种自然而然的激励以使得服务间通讯“批量化”,从而分担跨边界的开销。尽管这种批量化在某些情况下可能会增加延迟,它也能够简化组件间依赖,并且可能减少发生软件瑕疵的可能性,进而减少漏洞。

将软件作为微服务的集合来部署带来了一个基本问题:构建一种“可信微服务”是否有意义?更加具有雄心壮志的问题是,开发出能够作为其自身的引用监视器的微服务是否可行?引用服务器的概念始于 1972 年的 Anderson 报告 [Anderson72],并且指的是一种系统组件,它对于其所提供的资源的所有访问进行调度。引用监视器具有以下特点:1) 总是被调用;2) 防破坏;以及 3) 经过验证(即它足够小,以便被构建为具有高度担保)。随着微服务变得越来越流行,现在可能正是时机以研究制定关于可信的或是能够作为引用监视器的微服务的判据,以及理解微服务的架构结构的安全局限性。

通过使得组件依赖和相互作用更加显式化,微服务看起来带来了新的机会以实施基于干涉的安全增强。插入到这些微服务相互作用之间的封包层将会拥有能力以增强、转换、拒绝以及监视这些相互作用。这些能力可以被用于限制来自软件漏洞的潜在危害,但是,干涉也可能导致系统不稳定并且带来性能下降。一种可能的研究介入是调查与基于微服务的系统兼容的干涉策略。微服务提倡组件之间的简化接口(例如没有通过全局状态的内存共享)。这种简化可能使得基于微服务的干涉在执行时具有较少的与稳定性相关联的效果。

2.2.3 成熟度水平

虚拟化系统可以追溯至 20 世纪 60 年代。LXC 容器形式的虚拟化始于 2008 年,并且自此处于活跃开发之中。也存在若干替代的轻量级虚拟化系统,例如 BSD Jails、OpenVZ 以及 Oracle Solaris Zones。容器已经被实质性地部署于云端和服务器上。[脚注 1]

当前的微服务术语和设计目标出现于 2014 年。早期的表述方式,诸如运行于微内核之上的任务,可以追溯至创始于 1985 年的卡内基梅隆大学的 Mach 项目。自此以后,微内核技术成为了后续研究的主题,并且被整合进了大型商业产品,尤其是苹果 OS X。

[脚注 1] 操作系统容器有助于实现某些云机制,但是云计算完全不同于操作系统容器 [Mell11]。

2.2.4 可信度的基础

基本技术已经被广泛应用,并且对于容器配置的更多自动化有着公认的需求,因此会有需求拉动。由于容器可以被非常快速地创建、测试和删除,已有确凿的证据显示关于容器配置的大范围测试可以通过半自动的方式进行。关于微服务,微服务框架的数量的增长提示该技术的流行度正在增加,并且仍然有空间以进一步丰富微服务框架,以及使得这些新增的框架被采用。同时,微服务的模块化本质可能为部署更多安全版本的微服务而不会显著干扰对用户的服务提供道路。

2.2.5 潜在影响的基本原理

操作系统容器和微服务已经是国家信息基础设施的重要组成部分。鉴于使用它们所具有的明确的可管理性、成本以及性能方面的优势,有理由期待它们的应用持续扩展。这些技术的安全增强版本一经采用,可以对软件漏洞的利用行为产生广泛的抑制效果。

2.2.6 延伸阅读

2.3 附加软件分析技术

当前存在众多不同的工具和技术,既有开源软件又有私有软件,用于分析软件以及检查大量问题。它们中的很多可以通过诸如 Eclipse 等通用集成开发环境(IDE)来执行。但是,当前的工具面临若干种阻碍。IDE 有时并不会为工具提供某种“信息总线”以共享软件属性。每一种工具必须进行其自身的语法检查、构建其自身的抽象语法树(AST)、列出带有其范围和属性的变量,以及利用经过证明的事实或者不变量来“装饰”AST。有些工具基于通常的基础设施而构建,诸如 LLVM 或者 ROSE [Rose16],因此它们共享代码,但是它们仍然必须重复进行大部分分析工作。此外,几乎没有标准以允许,例如,一种语法检查器被替换为运行得更快的新的语法检查器。

附加软件分析指的是一种完备的方法以解决使用多种高级软件检查工具时遇到的阻碍。附加软件分析的目标是促成高度可用的分析模块的持续积累,这些模块随着时间不断累积,以持续改进部署于软件分析中的最先进的实践。附加软件分析分为 3 部分。其一,它是有文档记载的标准以允许算法和工具交换关于软件的信息。其二,它是一个框架或者架构以允许软件担保和评估工具的模块化和分布式开发。此框架拥有类似于知识发现元模型(KDM)[KDM15] 或者在人工智能(AI)中称为黑板的功能。其三,它是概念性的方法以聚合、相关或者分析工具和算法的结果和能力。附加软件分析的一项关键输出将会是新一代面向用户的工具,它们可以便捷地将来自不同工具和技术的输出整合起来,形成关于某一软件的统一的、更加完整的评估。

完整的附加软件分析能力必须辅助工具协同工作、提供构建块以强力推动新的工具开发,以及辅助工具之间的整合和互操作性。因此,它必须包含标准、框架和技术以合并分析结果。

2.3.1 软件信息表达与交换标准

软件担保工具推导并且存储关于程序的五花八门的信息。然而不幸的是,并没有被广泛接受的标准以用于信息的精确定义或者它们可能被如何存储。由于缺少标准,开发者必须执行英雄壮举以便在不同的分析工具和算法之间忠实地交换信息。

仅仅在工具之间往返传输位几乎不会带来任何好处,除非这些位传达了被各种工具以相同方式理解的信息。例如,“error”(错误)、“fault”(故障)、“failure”(失败)、“weakness”(弱点)、“bug”和“vulnerability”(漏洞)是相互关联但是各不相同的概念。如果没有标准,一个工具报告了某个 bug,而另一个工具可以将“bug”理解为指示相对于第一个工具的评估结果更高(或者更低!)的成功攻击潜力。

例如,一系列形式化定义的信息可能对于分析某个程序是相关的:

  • 在代码中的位置
  • 在某个特定位置可见的变量,以及变量类型
  • 在某个特定位置的可能的变量的值,这可能包括变量的值之间的关系,诸如 x < y
  • 调用轨迹和路径,即到达这一点的所有可能路径
  • 对于二进制文件和可执行文件块的源代码位置引用
  • 可能的弱点,例如可能的 BOF [Bojanova16] 或者将要用于 SQL 查询的未经过滤并且因此受到污染的输入
  • 断言、最弱的先决条件、切面、不变量等,以及
  • 函数签名,包括参数类别

程序分析可以被应用于软件开发的不同阶段,并且被用于程序在不同抽象层级上的表现形式。例如,工具可以运行于程序的静态结构,诸如其 AST 之上,也可以运行于呈现数据或者控制流的表现形式之上,甚至还可以运行于编码功能行为,诸如最弱的先决条件的语义表现形式之上。我们接下来依次查看这些类别中的每一种。

抽象表示:早期的静态检查器通常不得不包括其自身的用于构建 AST 的语法检查器以进行分析。然而,编译器编写者意识到了开发具有良好的文档并且可简易访问的通用中间表示(IR)的重要性。例如,GNU 编译器 gcc 的开发团队在 4.0 版本 [GCC16] 中引入了中间语言 GENERIC,这是一种语言独立的格式,用于以若干种语言中的任何一种来呈现源程序。作为另一例子,Clang 编译器 [Clang] 提供了一种具有良好文档的 AST,它可以由第三方插件直接访问,也可以被保存为某种通用格式,诸如 JSON,以便被第三方分析工具处理。其他提供了具有良好文档的转换格式的编译器包括 Frama-C [FramaC] 和 ROSE 编译器基础设施 [Rose16]。

中间表示:工具可以对距离由编译器生成的最终可执行代码更近的中间表示(IR)执行深度分析。例如,GNU 编译器定义了 GIMPLE 格式,其中原始源程序被分割为简单的三地址语言。类似地,Clang 编译器提供了 LLVM 位代码表示,这是一种有类型的汇编语言格式,并不依附于某种特定的处理器。其他的包括通用中间语言(CIL)[ECMA12] 和 Java 虚拟机指令集或者字节码 [Lindholm15]。Vine 中间语言是一种平台独立的机器语言 [Song08]。

语义表示:用于检查功能正确性属性的工具通常需要这样一种表示形式,它比上文讨论的表示形式更加适合于表达逻辑程序属性。尽管这样的表示形式不如 AST 以及编译器 IR 那样成熟,其中的少数已经于近年获得了流行度。例如中间验证语言 Boogie [Barnett05],它提供了诸如参数多态、全称量化和存在量化、不确定性选择,以及部分有序等特性,并且已经成为高级检查器的流行后端,既可用于诸如 C 和 C++ 等低级语言,又可用于诸如 Eiffel 和 C# 等高级面向对象语言。Boogie 程序可以被翻译为 SMT-LIB 格式 [SMTLIB15],这允许它们被任何支持 STM-LIB 格式的定理证明器检查。将通用语言用于语义表示的另一个例子是 Datalog [Whaley05],它已经被用于构建不同的工具以检查数组边界溢出、在多线程程序中查找竞争条件,以及检查网络应用程序安全性等。

2.3.2 工具开发框架或者架构

为了促成新工具的开发,附加软件分析要求初始构建块。关键的初始构建块是一种框架,它能够将工具或者技术的能力结合起来。正如 Eclipse 极大地促进了用于开发代码的 IDE 技术的改进那样,附加软件分析的框架将会致力于使得软件担保和测试工具的协同开发成为可能。此“框架”可以是独立的工具,也可以是某个现存 IDE 的插件或者更新。

宽泛地说,有两种用于框架的通常方法以在程序分析工具之间传递信息。第一种方法将某个检查器作为插件整合进现存的编译器工具链中。现代编译器框架,例如 gcc、Clang 和 Frama-C,使得编写新的插件变得简单。更进一步地,插件通常被允许更新某种 AST 或者中间形式,由此允许插件使得它们的分析结果对于其他插件可用。例如,Frama-C 编译器框架提供了一个插件库,它包含 use-def 和指针别名分析,这些对于编写语义分析器通常是必需的。第二种方式依赖于某种通过写入到硬盘或者通过网络发送以传递信息的通用格式。此方法的一个范例是证据性工具总线 [Rushby05],它允许由不同厂商制造的多个分析引擎交换逻辑结论以执行高级程序分析。信息应该被附加到代码以使其成为“随码担保”[Woody16]。某种附加框架将会同时支持两种信息传输方式以便尽可能多地重复利用现有成果。

本节中所引用的框架能力专注于在工具之间交换信息,而非 2.4 节讨论的框架的开发能力。

2.3.3 分析结果合并策略

有了适当的标准和框架,我们就能够获得通过累加或者合并不同的软件分析结果所带来的额外的好处。软件分析结果可以通过 3 种通常的方式累加起来。第一种情况简单地说就是获取更多信息。假设程序员已经拥有某种工具以检查注入 bug(INJ 类)[Bojanova16],添加一种工具以检查死锁可以为程序员提供更多信息。

第二种情况是确定性或者矛盾性。程序员可能拥有两种不同的启发式搜索以查找错误操作(FOP 类)bug [Bojanova16],它们各自拥有独立的几率以报告真实的 FOP bug 和假阳性。此架构可以用于对两种启发式搜索的输出进行相关以得到具有较少假阳性的单一结果。与之相反,一种工具可能会宣称某个语句可到达,而另一种工具则宣称并非如此。这种矛盾性可能指示二者的假设存在差别,或者某个工具中存在错误。某种工具使用的一系列演绎规则孤立地看可能具有一致性,但是与来自另一种工具的规则并不具有一致性。

附加软件分析的第三种情况是协同作用。某个在关于内存使用和数据结构的形式化推理方面具有特长的研究小组可以在由某个专长于对二进制代码进行“语法分析”的小组开发的组件的基础之上进行开发,由此创建一种能够对二进制文件的内存使用进行推理的工具。开发者可以更加快速地对混合和符号测试担保工具进行试验。例如,某个工具可能会使用静态分析器以获得可能存在的问题的代码的位置,然后利用约束满足问题求解器和符号执行来创建能够在每一个位置触发错误的输入。

2.3.4 分析结果合并技术

一旦经过训练,这样的神经网络自身可以作为漏洞检测引擎。来自手动分析的不正确结论是时间和资源密集的。为了保证高效,上述结果合并策略必须利用适当的技术在工具中实例化。例如,Code Dx [CodeDx15] 是一种用于匹配、合并并且呈现分析工具的输出的工具。更加强大的方法是应用机器学习技术,诸如微软的认知服务和计算网络工具包,以及 Google 的 TensorFlow 等。

执行深度学习和神经网络的训练和推理阶段所必需的底层硬件的价格已经显著下降。云服务现在可以按需提供高端图形处理器(GPU)实例。这样的计算能力显著增强了机器学习算法的速度,允许利用显著增大的数据集合对其进行训练,以及实现显著加快的训练和反馈循环。那些已经搜集了大量关于漏洞、漏洞利用、恶意软件、rootkit 以及后门信息的素材的组织机构可以利用众所周知的数据科学技术挖掘这些信息以推导出新的洞察力和价值。

一旦经过训练,这样的神经网络自身可以作为漏洞检测引擎。来自人类实践者的不正确结论可以被反馈回训练阶段以自动加强算法或者网络的辨别力,并且渐进式地改进它们。这些技术拥有在宽泛的语言集合中检测漏洞的潜力,包括那些新开发出来的,尚无良好建立的分析工具的语言,并且甚至可以检测出新的漏洞类别。

这种检测能力可以增强现存的工具链。更重要地,来自其他分析工具的结果可以成为这些强大技术的训练和分析的额外的信息来源。这些同样的网络,只要得到足够的资源,在实现识别并且优先解决具有风险的组件这一相同目标的同时还能够分析大片源代码。

2.3.5 成熟度水平

大多数常用的编译器,诸如 gcc、Clang 和 Frama-C,提供了添加用于处理和更新 AST 和 IR 表示的插件的内建支持。此外,大型社区已经开发出了广泛的库和插件,并且创建了带有入门教程和参考手册的百科网站以降低新用户参与其中的门槛。对于语义表示的情况,社区规模较小并且入门门槛较高,尽管诸如 Boogie 等语言已经被若干研究小组成功地用作引擎以构建用于多种语言的检查器,诸如 C [VCC13] 和 Eiffel [Tschannen11],甚至还可用于操作系统 [Yang10]。

有众多当前的软件信息交换系统,诸如 LLVM、ROSE、gcc 的 GENERIC 或者 GIMPLE,以及知识发现元模型(KDM)等。用于合并工具的输出的格式,诸如工具输出整合框架(TOIF)和软件担保发现表达纲要(SAFES)[Barnum12],已经暗示了关于软件的有用知识类别。

2.3.6 可信度的基础

当今领先的静态分析工具具有低假阳性率,这已经引起了其在业界和政府组织之间的更多采用。而这反过来又激励了编译器团队以增加对于那些能够对内部程序表示进行操作的插件的支持。有一些大型并且活跃的用户社区正在为接口编写文档,以及为那些能够被合并起来以构建复杂分析器的插件创建库。确实,挑战并不在于某种附加软件分析方式能否工作,而是在于投资哪一个,以及如何将它们捆绑起来。

2.3.7 潜在影响的基本原理

早期的静态分析工具检查的主要是程序的语法属性,强制执行编码指导原则并且查找对应于简单运行时错误的结构,诸如对空指针解除引用,或者在赋值之前使用变量。随着分析器变得更加高级,它们越来越依赖于对于程序结构和数据流的更加复杂的分析。允许用户构建能够共享和合并结果的小型分析引擎的常用框架将会使得构建高级分析器成为可能。这样的分析器可以发现隐晦的错误,而这样的错误难于利用传统的测试和模拟技术来发现。

这样的框架和标准应该允许模块化和分布式的开发,并且允许现存模块被替换为更好的。它们还应该有助于不同小组的研究人员之间的协同作用。它们应该加速工具的“生态系统”的成长以及下一代“混合”工具的开发。混合工具可以使用静态分析模块来查找有问题的代码的位置,然后使用约束满足条件求解器模块和符号执行引擎来创建能够触发错误的输入。不断增长的、共享的一系列有问题的和良好的编程结构和习惯用法可以最终由工具进行检查 [Kastrinis13]。

2.3.8 延伸阅读

  • [Bojanova16] Irena Bojanova, Paul E. Black, Yaacov Yesha and Yan Wu, “The Bugs Framework (BF): A Structured Approach to Express Bugs,” 2016 IEEE International Conference on Software Quality, Reliability, and Security (QRS 2016), Vienna, Austria, 1-3 August 2016, https://doi.org/10.1109/QRS.2016.29.
  • [Kastrinis13] George Kastrinis and Yannis Smaragdakis, “Hybrid Context-Sensitivity for Points-To Analysis,” Proc. 34th ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI ‘13), 2013, pp. 423-434, https://doi.org/2499370.2462191.
  • [Rushby05] John Rushby, “An Evidential Tool Bus,” in Proc. 7th international conference on Formal Methods and Software Engineering (ICFEM’05), Springer, 2005, p. 36, https://doi.org/10.1007/11576280_3.

2.4 更多成熟的领域特定软件开发框架

简单地说,此方法地目标是提升经过良好测试和良好分析的代码的使用(和重复使用),并且因此减少可被利用的漏洞的发生几率。

如同在 4.3.6 节叙述的那样,将可重复使用的软件组件组织进组件库或者版本库的理念至迟可以追溯到 1968 年 [McIlroy68]。为了使得软件可以重复使用,可共享的软件组件可以被打包进一系列构建块中,例如独立程序、服务、微服务、模块、插件、函数库、框架、语言(如 2.1.4 节注释)、类,以及宏定义等。一套这样的(传统)构建块通常构成了新的软件开发努力的起点。或者更加通俗地说:几乎没有任何东西是从头创建的。因此,新的软件系统的漏洞决定性地依赖于最恰当的现存组件的选择和应用,以及新代码与传统组件之间的相互作用。

尽管代码共享的单元可能很小,例如单个函数或者宏,使用成熟、高价值的组件可以带来实质性的好处,在此,代码清洁性、领域知识和代码质量方面已经进行了大量投资。

软件框架包含代码,以及更重要地,它还定义了利用它所构建的程序的软件架构(包括默认行为和控制流)。领域特定的框架还包括领域知识,例如 GUI 构建、语法分析、网络应用程序、多媒体和计划等。成熟的领域特定框架一旦被软件开发者学习,可以使得程序的快速生产成为可能,这些程序从软件视角以及领域知识视角来看都是经过良好测试的。在最佳案例场景中,在此,成熟的框架被专家恰当地使用,有实质性的机会以避免那些可能导致可被利用的漏洞的软件错误。

然而不幸的是,这种最佳案例场景难于实现。具体地说,为了实现成熟框架所带来的好处,软件开发者必须克服若干种重大挑战。

查找适合的框架:存在着太多的框架。例如,在 2016 年九月对 github.com 进行简单的搜索,即显示了超过 171000 个版本库,在其名称或者描述字符串种包含单词“framework”(框架)。(尽管这些架构中有一些反映出了其在设计清洁性和质量方面的巨大投资,其它的则是被仓促构建的、具有不可知的来源,或者可能是恶意的。)这些框架通过范围宽泛的编程语言(PHP、JavaScript、Java、Python、C# 和 C++ 等)实现,并且众多框架使用多种编程语言。额外的复杂度来源于包管理器和构建系统的多样性,这种多样性必须被潜在的框架客户端学习。软件开发团队面临巨大挑战,而只是为了调查可能支持某个项目的要求的可能的框架;这种挑战是足够急迫的,以至于有一个项目 [TodoMVC16] 的存在完全是为了帮助开发者在可用的(模型视图)框架中作出选择,通过出于比较的目的显示一个由多种框架实现的示例应用程序。在受到调查的框架中评估其适用性是一种更进一步的挑战。众多框架在其构建进程中包括某种形式的测试,通常是单元测试 [Beck94]。这样的现存测试需要被评估其相对于某个项目的目标的充分性。一个更进一步的问题是,不同的平台提供不同的安全特性(例如访问控制列表、签名的可执行文件以及白名单等)。对于框架对某种特定平台的要求程度,选择该框架时必须考虑对于平台特定的担保特性的理解和使用。

学习新框架:Brooks 说过,软件包括了“基本”和“偶然”的信息 [Brooks95]。基本信息是关于算法和软件所必须执行的基本操作的。偶然信息是关于接口细节、编程语言的选择、在系统中为元素取的名称等等的。每一种框架都包含这两种信息,这必须在专家水平被理解,以使得框架被安全地应用于非平凡的应用程序。尽管专家可能已经知道关于某个问题领域的大部分基本信息,偶然信息不能被预期。

对于一种通用数据结构,列表的快速精读展示了这种基本的困难。列表的涵义被大部分软件开发者所熟知,但是实际创建并且使用列表数据结构所必需的信息在相互竞争的环境之间大不相同。例如 Unix 的 queue.h 宏、Java 集合、JavaScript 数组、Python 的内建列表,以及 C++ 标准模板库中的列表模板等,它们都实现了相同的基本理念,但是使用大不相同的细节。一位软件开发者对于列表的概念以及某些列表实现可能是专家,但是对于在新框架中的具体的列表实现的使用而言则可能完全是个初学者。因此,这位开发者必须花费时间以低效地学习(通常是大量的)偶然信息。如果开发者受困于计划压力而最小化这项预备工作,基于框架的初学者级别的软件可能被制造出来,它更有可能包含瑕疵和漏洞。

理解并且控制依赖:一种框架可能依赖于其他框架,由此得到的依赖传递图可能是庞大的。框架用户可能会在其依赖于可能是庞杂的框架代码的项目中轻易发现漏洞,这些代码被自动包括进来,或者通过传统的包管理器和构建系统间接包括进来。2016 年的“leftpad”事故展示了这种危险性。被重度使用的 Node 包管理器维护着不计其数的包,它们可以被 JavaScript 程序轻易地引用和使用。当一起所有权争论于 2016 年爆发时,一位开源作者从 Node 包管理器中反发布了他的超过 250 个模块。其中之一就是微小的函数“leftpad”,它向字符串中添加填充的空格或者零。数以千计的程序,有些是非常重要的,依赖于“leftpad”并且突然不能工作,直到被反发布的包再次被“反反发布”[Williams16]。

解决框架组成的不兼容性:多种框架可能不能同时应用于同一程序中,或者即使它们可以,其包含顺序或者版本可能很重要,由此导致脆弱的代码。在其他案例中,诸如 lex/yacc 代码生成工具,显式的操作是必需的,以避免名称空间冲突,进而允许框架的多个实例共存于一个程序中。这样的冲突可能是隐晦的,如同 Lampson 所指出的,每一个组件可能拥有不同的“世界观”,而 n 个组件的组合可能得出 n2 种相互作用 [Lampson04]。

这些是长期存在的挑战。更进一步地,由于当前可用于开源的框架(具有不同的来源和质量)的巨大并且仍在增长的数量,这些框架通过由诸如 GitHub、JIRA、Bitbucket、CollabNet 等版本库管理实体托管的公开版本库而可用,选择一种适合的框架的困难可能会更加急迫。然而,这种广泛的使用同样表现出了重要的机会:如果在框架如何被发现、学习、进行依赖管理和编写等方面可以取得哪怕是微小的改进,很多软件漏洞就可以被避免。

另一个显著的进展是,通过利用诸如 stackoverflow 或者 stackexchange 等软件问答网站进行复制/粘贴操作的软件开发方式(包括框架使用)成为主流。尽管基于问答的代码重复利用可能是快捷的,它也可能导致理解不良和整合不良的解决方案。获得关于提出的问题的答案和示例代码的能力可以明显地有助于开发者的理解,然而,需要技术以便在采用他人的解决方案时避免产生漏洞。

尽管这些是巨大的挑战,当前的最先进技术提供了机会以撬动现存的代码以及技能资源,同时利用新的技术和工具以增强它们。

2.4.1 快速框架采用

框架的采用很明显地受到了需要学习大量偶然信息这一点地阻碍。Gabriel 将“宜居性”定义为“使得程序员、编写代码者、修复 bug 者和人们在代码的生命后期来到该代码时能够理解其构造和意图并且舒适地以及满怀信心地更改它的源代码特征”[Gabriel96]。由于意识到了实现宜居性的挑战,Gabriel 提议使用软件结构以帮助开发者快速理解现存代码,并且标记出负面实践的使用。尽管不是一种万灵药,结构(例如 [Gamma95])可以有助于将框架提供者和框架消费者之间的鸿沟桥接起来。有助于实现这一点的一种方式是开发一系列涵盖了流行领域的结构。2016 年九月关于 GitHub 上的前 10 名最流行(“星级”)和最多“分叉”的版本库的非正式调查显示了围绕这些方面的显著框架活动:网络应用程序开发、前端网络开发、操作系统内核、跨平台应用程序框架、虚拟机管理、编程语言和异步 http 服务器。加速其采用的一种方式是制定关于这些领域中的某些的软件结构,其焦点是协调不同框架之间的偶然信息(于是它无需被学习很多次),并且制造关于通常应用案例的文档。随后可以进行实验以测定其有效性,通过比较有和没有新的结构信息时的架构使用情况。

2.4.2 高级测试方法

除了民航(在此领域,软件被根据极其严格的美国联邦航空管理局(FAA)标准而构建和测试)的特例以外,商业软件通常只会得到最小化测试。那些将上市时间作为其至高无上的目标的行业尤其如此。测试可能被局限于只有关于必要的功能已被实现这一点的基本担保,有时被称为“快乐路径”,或者积极测试,它们展示了功能,但是并不提供关于不良行为并不存在这一点的担保。

高级测试方法坚守显著增加框架强壮度的承诺,并且更进一步地,构建关于在与依赖相关的不同假设之下的框架组成的担保。众多框架当前只采用临时安排的测试。其他一些框架则采用标准单元测试 [Beck94],并且实践于不同的完整性级别。自动化的测试,诸如 QuickCheck [Claessen02] 或者不同的模糊工具可用于大多数语言。关于传统测试套件的覆盖度测定的最近进展提供了机会以比较框架。组合测试将大量输入值的组合压缩为少数测试 [Kuhn10]。框架可以被自定义或者配置的众多方式提示了一种在软件框架应用中获得新的可信度的可能方式。通过展示高质量的组合,这样的测试拥有潜力以强调框架的相似性,降低学习曲线并且允许经过良好测试和良好分析的代码的更宽泛的采用。

2.4.3 多框架组成中的冲突解决

在某些案例中,多种框架可能被并行使用而不会产生冲突。在其他案例中,允许并行使用的组成可能是脆弱的。居于主导的框架结构,诸如控制反转(IoC)[Busoli07]——又称为好莱坞原则:“不要调用我们,我们将会调用您,”可能会加剧这种情况,由于每一个框架可能会假设是由它在整个应用程序中定义控制流。一种化解方式是虚拟化框架操作,利用例如轻量级操作系统容器 [LXC] 并且随后在并行执行的框架之间建立通讯链接。另一种冲突解决的方式是使用软件翻译来重写框架,以使得它们的重叠元素各不相同。先期努力可以展示这些以及其他解决冲突的策略的可行性,并且比较它们的成本以及对于应用程序漏洞的影响。

2.4.4 成熟度水平

关于软件结构的文献极其广泛,并且软件测试是计算机科学中的一个相对成熟的子领域,至今已经被实践了 40 多年。框架本身现在是软件共享中的主导单元。上述 3 种技术:结构、测试和框架,正在持续的使用和详细化进程中。

2.4.5 可信度的基础

毫无疑问,可以为若干种主要框架的结构编写文档;快速的采用可能更多地是渐进式的进展而非革命性的进展,但是,渐进式的进展应该从投资流向结构文档。将会受到框架组成的影响的高级测试技术是相对成熟的,这增加了关于框架整合可以被有效测试的可信度。

2.4.6 潜在影响的基本原理

代码重复利用是无处不在的,并且看起来正在加速;通过对非常流行的框架进行投资,任何进展都会变得广泛相关。

2.4.7 延伸阅读

2.5 移动目标防御(MTD)和自动软件多样性

此方法是一系列技术的集合,以自动改变软件的细节结构和属性,使得攻击者在利用任何弱点时的困难大大增加。为了说明,考虑此家族中最近被提议的技术之一:堆内存随机化 [Iyer10]。当程序请求一块缓冲时,最简单的方式就是返回下一段可用的内存中的一块。这将缓冲置于相同的相对位置。如果知道了这一点,攻击者可以利用一块缓冲中的缓冲区溢出弱点(即 BOF 类)[Bojanova16] 以便,例如,读取总是位于该缓冲之前 384 字节处的另一块缓冲中的口令。堆内存随机化将会在每一次分配过程中分配随机数量的额外内存。这将缓冲置于不同(不可预测)的相对位置,于是上述漏洞利用的难度大大增加,或许根本不可能。

软件多样性和移动目标防御(MTD)的目标是降低攻击者利用软件中的漏洞的能力,而非减少软件中的弱点数量。这种降低可以通过改变“攻击面”而实现,攻击面即可供攻击者访问的跨越时间(在操作过程中发生更改)或者跨越副本(多样性)的接口。这种降低可能还包括再生受到攻击的系统组件 [Knight12]。

当然,多样化必须是安全的。即发生的更改对于正常行为没有影响,而非可能增加资源使用。即使加上这一条约束,我们仍然可以牺牲计算能力以换取多样化中增加的粒度或者完全程度。增加的粒度被预想为能够针对未知漏洞利用提供更好的保护,由于具有较高的几率以影响对于攻击至关重要的某些信息片断的位置或者值。这种折衷类似于静态分析,参见 2.1.1 和 2.1.2 节:投入的资源越多,担保的量就越大。区别在于,静态分析找到特定漏洞以使得它们可以被修复,而导致多样化的变换增加了利用整类漏洞的难度。

2.5.1 编译时技术

编译时技术时那些由编译器自动应用的技术。它们可能引起每一次编译得到相同的可执行文件,以使得可执行文件随后在运行时选择随机的行为或者内存布局,或者它们也可能引起每一次编译得到不同的可执行文件。

一些特定技术包括数据结构布局随机化、函数调用中的不同的参数顺序、地址空间布局随机化(ASLR)[PaX01]、指令集随机化、数据值随机化、应用程序关键字标记,以及具有操作混淆和重构的可变指令顺序。

对于证明这些多样化是安全的这一点有用的程序信息对于旨在发现或者移除漏洞的程序分析同样有用。附加软件分析方法,如 2.3 节所详细叙述,是为了使用相同的计算能力以同时检测或者移除弱点,并且也会随机化剩余的弱点。这些多样化技术可以通过附加分析框架以捆绑进静态分析工具,从而潜在地只需要极少的资源开销。

然而不幸的是,当今没有工具做到这一点。分析软件通常由程序员在开发时运行。多样化通常只会在系统测试阶段或者操作阶段当其显示了弹性的时候展示出它的好处。往坏里说,多样化为测试结果增加了歧义性,并且使得追踪造成故障的根源变得更难。为了反制这种努力和好处之间的脱节,使用了多样化的程序应该被特别致谢,以使得消费者知道它们使用了一个额外层级的弹性。那些产生了极度多样化的结果的编译器同样将会减少对手通过检查某个程序的最新和先前版本之间的差异来发现漏洞的几率:它们将会过于不同 [Franz10]。

2.5.2 系统或者网络技术

某些位于系统或者网络层级的技术包括网络地址空间随机化和协议多样性 [Rowe12]。它们可能在其根据规则基础发生变化时成为动态的。在众多案例中,这些技术是基于对于从服务到地址的共享秘密地图或者共享秘密密钥的假设而构建的,以使得应用程序可以认证并且获得当前信息。

2.5.3 操作系统接口技术

操作系统(OS)可以对不同的进程呈现不同的接口。这些接口可能是动态的,诸如为每一个系统服务指认的随机中断号,也可能是静态的,其中 OS 对于每一组服务拥有若干种选择。在动态情况下,链接器/加载器可以将每一个新的可执行文件调整至为该进程作出的指认处。作为静态情况的一个范例,OS 为新的进程呈现了一组 j 种内存管理 API、一组 k 种进程服务、一组 m 种网络函数,以及一组 n 种 I/O 调用。试图执行通过该进程的入侵代码将会不得不应对 j × k × m × n 种不同的 OS 接口以获得成功。

2.5.4 成熟度水平

一些移动目标防御是当今众多操作系统和编译器的默认值。有大量研究和整场会议专注于理解当前技术的局限、成本和好处,并且开发新的、更好的技术。

2.5.5 可信度的基础

就挫败的攻击数量、吓退的攻击者,或者攻击者所必需的额外资源而言,这些好处是未知的。然而,众多 MTD 技术可以被自动应用,例如由编译器来应用,几乎不用付出资源或者运行时间的代价。

2.5.6 潜在影响的基本原理

MTD 技术可以被应用于当今的大多数程序和系统,甚至是静态嵌入式系统。因此,其好处的范围是非常大的。其影响并不明确,由于大多数技术增加攻击者的成本,而非严格意义上地消除漏洞。

2.5.7 延伸阅读

第 3 章 测定和度量

本章在最宽泛的意义上处理测定、评估、度量、鉴定、判断、评价等。因此,代码审查、软件测试和其他技术在本章中具有一席之地。如同我们接下来所讨论的那样,缺少经过精确定义和严格验证的测定方法,更糟的是,大多数现存的测定方法对于我们想要在软件中确定的高级属性而言只有中等程度的预测性。甚至没有广泛和详细的数据,诸如漏洞的数量和类型,以使得测定研究可以基于它们进行。

我们有 3 个关注的领域。其一,鼓励使用测定。世界上的所有非常规测定方法如果无人使用它们,就不会带来任何帮助。同样,无人 可以 采取测定行动,如果该测定方法并未被制造出来因而成为可用。美国联邦政府可以促进并且鼓励使用软件产品测定。其载体包括采购、合同、责任、保险以及标准,如同 4.3 节所解释的那样。测定带来的好处将会被放大,如果它们在受到训练的软件开发过程中被修订、解读和使用 [Curtis16]。确实,良好的测定方法的广泛使用是少数方式之一,这些方式具有打破崩溃——补丁的轮回以及超越攻击者的潜力 [Grigg08]。软件也会得益于第三方、非政府组织的程序和判据。某些可能性包括 UL 网络安全担保计划(CAP)、信息科技软件质量联盟(CISQ)的代码质量标准、Coverity 扫描、核心基础设施倡议(CII)的最佳实践徽章,以及在成熟度模型中构建安全性(BSIMM)等。这些中的很多包括进程测定,这是第二个关注的领域。

第二个领域,进程测定,包括努力的小时数、更改的数量,以及在送达的代码中没有验收测试缺陷以及验收测试缺陷密度 [Perini16]。这些对于漏洞数量并没有直接影响,但是其间接影响巨大。例如,如果开发者被强迫频繁超时工作以赶上某个期限,或者计划安排不允许培训,则漏洞的数量很可能会显著增加 [Perini16]。其他范例包括指示新的过程步骤相对于先前的实践能够带来多少帮助的测定,或者指示过程中的允许漏洞逃逸的部分的测定。这种持续改进过程的方法被发现于最高等级的成熟度模型中。它还允许小组采用或者适应于对于他们的环境最为适用的方法和测定。我们不再进一步讨论进程测定。

最后一个关注的领域是对作为产品的软件的测定,例如,关于不存在缓冲区溢出的证明、每 1000 行代码中的缺陷数量、关于规范被满足的担保,以及通过测试套件实现的路径覆盖率等。美国国家标准技术研究所(NIST)的软件质量小组组织了一次关于用于减少安全漏洞的软件测定和度量(SwMM-RSV)的研讨会以征集想法,关于美国联邦政府可以如何最好地识别、改进、打包、带来或者提升软件测定方法的使用以显著减少漏洞 [脚注 2]。他们召集了简短的状态报告书,随后邀请了基于所提交的 20 个状态报告中的 10 个的研讨会演示。此研讨会举行于 2016 年七月 12 日,完整的研讨会报告可以作为 NIST SP 500-320 而获得 [Black16]。本章的大部分内容来自于此研讨会的成果。想法通常由一人提出,由其他人讨论和详细叙述,然后由另一些人编写并且报告。因此,在大多数情况下难于将想法署名给特定的个人。我们感谢参与了此研讨会并且对报告中所注释的想法作出了贡献的所有人,无论贡献大小。

[脚注 2] 其网站为 https://samate.nist.gov/SwMM-RSV2016.html

我们区分基本测定和导出测定。基本测定是具有明确的值的简单、基本的评估或者计数。与之相反,导出测定是“两个或者更多的基本测定的值的函数”[ISO15939],或者是某个基本测定的数学变换 [ISO25040]。导出测定通常是那些我们想要能够测定的属性的替代品。例如,缓冲区溢出(BOF 类)[Bojanova16] 弱点的数量是一种具有合理地清晰的定义的基本测定。与之相反,代码安全性是一种导出测定,它只能微弱地通过 BOF 数量进行预测。缺陷的不存在并不指示着卓越的存在。

3.1 软件测定分类法

软件测定可以从 4 个维度来分类。第 1 个维度是该测定方法有多么“高级”。低级测定是语义之下的,诸如程序的大小、路径的数量和函数的扇入/扇出等。高级测定方法更多地处理的是程序的本意是要实现什么。第 2 个维度是静态还是动态。静态测定是那些应用于源代码或者“二进制文件”本身的测定方法。动态测定应用于程序的执行。第 3 种维度是视点。可以是外部视点,有时称为黑盒或者功能性的,或者是内部视点,在此代码被考虑,称为白盒(“清晰”或者“透明”)或者结构性的。第 4 个维度是测定的对象:bug、代码质量和一致性。

对于第 1 个维度,测定方法可以分为低级或者高级的。低级测定方法被广泛使用。与之相反,高级测定方法所处理的是作为客体的程序与作为有意识的主体的开发者或者用户之间的关系。质量在这种客体和主体的相互作用之中得到提升 [Pirsig74]。与低级和高级测定方法形成类比的是低级漏洞和高级漏洞。某些低级漏洞包括缓冲区溢出、整数溢出和未能提供默认的 switch 语句的 case 等。这些低级漏洞可以直接从代码中识别出来,即某人可以检视代码,或者使用某个程序来检视代码,并且确定对于给定的特定输入是否有可能出现 BOF。无需引用某种规范、要求或者安全策略来确定缓冲区溢出是否为可能。

另一方面,高级漏洞不能仅仅依靠参考代码而被识别出来。人类审查者或者静态分析器必须查询要求、规范或者策略以确定高级问题。例如,未能加密敏感信息通常不能完全通过代码检查而被识别出来。当然,启发式搜索是可能的。例如,如果某个变量被命名为“password”,静态分析器如此猜测是合理的,即该变量是某个口令并且不应该在没有保护的情况下被传输,也不应该可以被非授权用户访问。然而,不论工具还是人类都不能在不对其进行外部定义的检查的情况下确定某个被命名为“ID”的变量中的信息是否应该被加密。

拥有对于安全策略和要求文档的访问并不会使得软件质量在所有案例中被评估。要求文档通常应对的是程序的行为,以及程序特有地需要去做什么。形式化地指定该代码应该是高质量的这一点是困难的,也许完全不可能。软件架构是定义结构组成的一种方式,它将良好的、有用的软件同易出错的、难于调试的、脆弱的或者不灵活的软件区分开来。

对测定方法进行分类的第 2 个维度——静态还是动态——在测试中最为明显。测试测定在概念上有两部分:测试生成或者选择,以及测试结果评价。测试测定通常回答这样一个问题,即程序(内部)或者输入空间(外部)有多少被使用了?测试案例生成必然是静态的,而评价通常是动态的,即基于执行结果。在众多测试测定中,这两部分彼此联结。它们可能包括某个例如选择额外的测试案例以增加覆盖率的步骤。因此,动态部分会影响静态部分。测试通常被引用为动态技术,由于程序执行是测试的重要组成部分。即如果某人提出了测试案例 但是从未运行它们,则严格地说不会得到任何担保。当然,在大多数案例中,选择测试案例过程中的思考和检查是一种静态分析,它产出了关于程序的某些担保。ISO/IEC 25023 将静态测定引用为内部测定,而将动态测定引用为外部测定 [ISO25023]。

第 3 个维度是视点,可以是外部或者内部的。外部测定通常是关于规范、要求或者限制的行为一致性。它们基于软件被观测到做了什么。它们通常被引用为“黑盒”或者行为性的。这些测定方法对于验收测试以及估计用户或者任务满意度极为有用。如果程序不能满足其目的,该程序编写得多么好或者其内部结构组织得多么好几乎没有任何意义。与之相反,内部或者结构性测定主要应对的是代码的架构、实现以及精细粒度操作,或者得到关于它们的信息。内部测定基于对源代码或者可执行文件的分析。此类测定方法与质量相关,诸如可维护性、可移植性、优雅性和潜力等。例如,外部计时测试可能不足以确定算法的复杂度,而代码检查可以清楚地显示该算法的复杂度为 Θ(n2),并且对于较大的输入会有性能问题。

确定多少测试才是足够的同样展示了内部和外部测定的区别。外部测定,诸如边值分析 [Beizer90] 和合并测试 [Kuhn10],考虑行为或者规范以计算已经测试了多少,或者还有什么尚未测试。另一方面,内部测定包括区块数量计数、变化充分性 [Okun04] 以及覆盖率测定 [Zhu97] 等。这两种方式是互补的。基于外部的测试可以发现缺失的特性,基于内部的测试可以提出从要求来看并不清楚的案例,例如,当存在众多项目时由插入排序切换到快速排序。

对测定方法进行分类的第 4 个维度在概念上将其分为 3 类。第 1 类测定是存在(或者不存在)特定的弱点,诸如缓冲区溢出(BOF 类)或者注入(INJ 类)[Bojanova16]。注意,瑕疵的不存在并不指示例如弹性架构等。第 2 类是质量测定,其本意是确定代码或者部分代码的优秀性,然而,我们仅仅拥有“质量”的代理,例如可维护性、可移植性以及断言的存在等。即使如此,这些代理中的很多只能间接估计。前两类是关于产品质量的特征 [ISO25010]。第 3 类是与规范的一致性或者正确性。这第 3 种测定用于使用特征中的质量 [ISO25010] 并且必须具体到每一项任务。有可用的通用要求语言和检查方法。由于这 3 种类别之间的深刻差别,没有一种安全性或者漏洞测定方法可以保证优秀代码。

3.2 软件担保:软件测定的目标

关于软件将会按照其所应该的方式发挥功能的担保有 3 个来源。其一是开发过程,如果软件由拥有明确要求、经过良好培训并且已经被证明能够构建具有低漏洞率的良好软件的团队开发,那么我们就能够拥有关于他们所生产的软件很可能具有极少漏洞的信心或者担保。担保的第 2 个来源是我们对于软件的分析。例如,代码审查、验收测试和静态分析等可以为我们保证该软件的漏洞很可能是稀少的。我们可以牺牲这两种资源以换取担保。如果我们几乎没有任何关于开发进程的信息,或者该开发进程在过去并未产出良好的软件,我们必须进行多得多的分析和测试以获取关于软件质量的信心。与之相反,如果我们对于开发团队和开发过程拥有信心,我们只需进行最小化的测试以确保该软件能够遵循过去的经验。

软件担保的第 3 个来源是弹性执行环境。如果我们对于软件质量没有信心,那么我们可以在容器中运行它,如同 2.2.1 节所解释,给它极少的系统权限,并且让其他程序监视其执行。如果任何漏洞被触发,则它对系统的危害是受到控制的。

我们可以利用数学公式来表达我们的担保:A = f(p, s, e),其中 A 为我们所拥有的担保的量,p 为来自我们关于其进程的知识的担保,s 为来自静态和动态分析的担保,而 e 为我们通过严格执行环境所获得的担保。合并函数 f 为某种加和运算,类似于 p + s + e。如同我们之前所述,如果我们没有关于进程的信息,则可以通过额外的分析工作来提升我们的总体担保。另一方面,如果我们对于开发软件的进程(和人)拥有巨大信息,则我们不需要进行那么多的分析工作。

3.3 软件计量学

为了拥有一种合乎逻辑的、广泛有用的测定系统,某人必须拥有坚实的理论基础,即软件测定的哲学。这种哲学必须拥有坚实的数学基础,例如,以使用合理的统计 [Böhme08]。本节解决了诸如这样的问题,即什么是软件计量学?它的目的是什么?相对于物理测定,测定软件过程中所特有的挑战是什么?可能的解决方案或者潜在的方法是什么?

软件测定方法拥有众所周知的理论局限性,与物理学中的海森堡不确定性原理相类比,计算机科学拥有停机问题、莱斯定理,及其相关结果,它们展示了正确地确定 所有 可能的程序的感兴趣的测定结果是不可能的。尽管这是一种提醒,这并不意味着所有有用、精确、准确的测定都是不可能的。有若干种方式以避免这些理论障碍。其一,我们可以满足于相对属性。能够确定某个程序的新版本相对于之前的版本更加安全(或者不那么安全!)可能会有所帮助。我们并不需要关于某个程序的安全性的绝对测定结果。其二,某项测定可能仅适用于拥有“合理的”结构的程序。某项测定仍然会有用,即使它不适用于那些完全由数以百万计的散布着变幻莫测的计算的条件的 go-to 语句构成的程序。无人(应该)编写这样的程序。最后,社会可以就特定应用程序作出决定,而我们只需要构建可测定的软件。民用建筑师不会被允许设计具有随意的拱门、穹顶、悬臂和正面的建筑。他们会被要求运行分析以展示该设计能够承受预期的负载和力,然后建设才能开始。当前,大多数程序员学习编写“优雅”软件,然后试图展示它能够工作。期望可能会发生更改,以使得专业人士只会编写那些能够明确满足其限制和要求的软件。

计算机程序员有时会半严肃地使用片语“这不是 bug:这是特性”。它强调了 bug 和特性是在某种意义上相互关联的实体。让我们假设某个程序可以被表征为一系列特性。(程序是一系列特性这一理念是某些大小测定的基础。例如,函数点测定试图捕获某个基本操作或者功能的理念。)称某个程序“有一个 bug”意味着它是某个“良好”程序的有 bug 的版本。良好的程序和有 bug 的程序都是程序。根据这一假设,两个程序都是一系列特性。因此,良好的程序和有 bug 的程序之间的区别在于某些特性的集合——添加、移除或者更改的特性。因此,精确的定义是:bug 是理想的特性和现存的特性之间的区别。在众多案例中,一个 bug 可能只是某个额外的特性,或者是取代另一个特性的特性。

我们可能会将软件计量学和物理计量学对立起来。在物理计量学中,挑战在于精确并且可重现地确定物理对象、事件或者体系的属性。与之相反,对于软件,大多数所谓的测定只是计数。一个恰当的案例是,ASCMM-MNT-7:模块间依赖循环拥有精确定义 [OMG16]。不难编写这样一个程序以精确测定实例数,在此,某个模块拥有循环回某个软件的引用。这样,差别就在于物理计量学已经明确标识出了他们想要确定的属性,例如质量、长度、时间和温度等。与之相反,软件计量学拥有一道完全不同的鸿沟。我们想要测定高级属性,诸如质量、可维护性和安全性等,但是我们并没有关于这些的精确定义。因此,我们不能直接测定它们。然而,我们可以测定与这些高级属性相关联的众多属性。

当前,计量学将实体数量计数降级为一种用于确定属性的第二类方法。这样的经过计数的 全部被视为相同的一维的量,有时被称为无量纲量,尽管它们可能具有不同的 类型

3.4 产品测定

如同良好的进程对于生产具有极少漏洞的代码至关重要那样,终极能力是测定代码本身。如同本章绪言所指出的那样,对软件本身的测定可以为进程改进提供信息。

安全性或者漏洞测定在其最宽泛的意义上包括测试和检查。我们需要这样的测定以确定此报告中的目标是否实现!采用此报告中给出的任何一种技术可能不会显著减少漏洞。未能实现减少漏洞可能只是由于关于技术如何使用的某些细节问题,或者可能是由于该技术就是不适用。如果采用了若干种技术,区分每一种技术的效果或者其共同效果甚至会变得更难。

这样的测定不能被留到开发的最终阶段才进行。它们必须被包括到软件开发的 所有 阶段。除了像净室方式 [Mills87] 这样的充满雄心壮志的方法以外,此类测定不能作为门而被留到接近开发周期的结束。

有这样的可能性,即软件质量和安全性测定对于减少软件漏洞而言可能是错误的重点。某些测定可能会渐渐显露为重点,由于其他测定方法可能具有内聚性以及麦凯布循环复杂度。也可能证实最佳方式就像净室,在此,测定方法告知一种决定,以接受或者拒绝,并且不会宣称其创建了关于没有错误的绝对认证。

3.4.1 现存的测定方法

有数以百计的被提议的软件测定方法,诸如代码行数、类耦合性、封闭类的数量、函数点、更改密度,以及内聚性等。它们中的大多数并未经过精确定义或者严格验证。更糟的是,它们中的大多数对于软件中的我们所希望确定的高级属性只是具有中等程度的预测性。例如,代码行数(LoC)只是捕获了程序能力中的某些方差。同一规范在同一语言中的 LoC 可能相差多达 4 倍,即使所有程序员都拥有相近的技能。另一方面,LoC 与程序中的 bug 具有显著的强相关性。(这提示高级语言和领域特定语言一般会产生较少的 bug,由于它允许程序员更加精炼地表达功能。)

有些事情即使看起来就像在程序中数 bug 那样简单,其实也是令人惊讶地复杂的 [Black11b]。哪怕只是主观地定义什么是 bug 也很难。例如,某人可以编写一段永远不会发生整数溢出的二分搜索算法,但是该代码难于理解。除以零可能拥有良好定义的行为,得到特殊值“非数”,但是这通常不是一种有用的结果。bug 通常是若干种困难的级联反应。假设 (1) 未经检查的用户输入导致 (2) 整数溢出,进而导致 (3) 正在被分配的缓冲太小,进而导致 (4) 缓冲区溢出,最终导致 (5) 信息泄露。我们应该将此计为 1 个还是 5 个 bug?如果程序员在若干位置犯了同一个系统性的错误,例如未能在使用资源之后将其释放,这是一个问题还是若干个问题?与其说是例外,这些复杂性不如说是软件的规则 [Okun08]。

对于任何现实的程序,测试每一种可能的输入是不可行的。与之相反,必须选择一种测定方法以跨越整个空间。这些测定方法包括输入空间的合并覆盖 [Kuhn13]、变化充分性 [Okun04]、路径覆盖率测定 [Zhu97] 和边值分析 [Beizer90] 等。这些测定方法相互关联。例如,某些级别的(静态)合并覆盖能够制造那些产生了完整分支覆盖的测试,即一种动态测定方法 [Kuhn15]。

有太多的被提议的测定方法难于评估,甚至哪怕只是在这里列出来。我们可以说,如同上文所暗示,测定方法应该紧密地基于良好建立的自然科学,并且拥有合理的计量学基础,以获得最大的实用性 [Flater16]。

3.4.2 更好的代码

用于减少安全漏洞的软件测定和度量(SwMM-RSV)研讨会上的两则演示,Andrew Walenstein 的“测定软件的可分析性”和 James Kupsch 的“应对对于静态分析不透明的代码”指出了新的软件测定方法的方向。两则演示都强调代码应该能够被自动分析。两则演示都呈现了方法以定义代码能够被容易地分析这一点意味着什么、为何可分析性对减少漏洞有贡献,以及可分析性可以如何被测定和增强。

编程语言的部分子集被设计为可分析的,诸如 SPARK,或者被设计为不那么容易出错的,诸如 Less Hatton 的 SaferC。研讨会参与者普遍倾向于使用更好的语言,例如,函数式语言,诸如 F# 或者 ML。然而,对于未来并没有特别建议的 某种 语言。

我们注意到,除了少数特例,诸如拥有 SPARK 的 Ada 2012 [Barnes13] 以外,其他新语言的工具支持欠佳。支持新工具的构建对于新语言的采用和安全使用至关重要。

尽管基于代码的测定方法是重要的,我们可以期待从对于软件的其他方面的测定中得到互补的结果。某些方面包括软件架构和设计侵蚀测定、代码的语言方面、开发者的背景,以及与软件要求相关联的测定方法等。

3.4.3 二进制文件和可执行文件的测定方法

某些研讨会参与者认为,存在着对于二进制文件和可执行文件的测定方法的显著需求。由于有了今天的优化编译器以及对于二进制文件中带来的众多库的依赖,仅仅检查源代码为所有类型的漏洞的出现留下了通到。

3.4.4 更加有用的工具输出

今天,有众多强大并且有用的软件担保工具可用。没有单一的工具能够满足所有需求。因此,用户应该使用若干种工具。这是困难的,由于工具拥有不同的输出格式,并且使用不同的术语和类。工具输出应该被标准化。即通用的命名法、呈现形式和细节越多,用户就越有可能将工具的结果和其他软件担保信息合并起来,并且选择一种对他们最为有利的工具组合。

此外,工具可以提供关于它们的分析的更多信息。工具可以指示哪部分代码已经被完整地检查,而哪部分还没有,例如由于复杂度或者启发式搜索等。这类检查信息可以被附加到代码,使其成为“随码担保”[Woody16],与随码证明相类比。

参与者们感受到了对于科学地有效的研究的需求,研究内容包括工具的强度和限制、允许公开第三方对于工具的评估的机制、分享关于工具的洞察力的通用论坛,可能甚至还有关于经过验证或者认证的工具的列表。

3.5 延伸阅读

第 4 章 非技术方法和总结

作为对 2016 年二月的美国联邦网络安全研发战略计划的回应,OSTP 请求 NIST 标识出可用于显著减少软件漏洞的方式。NIST 与软件担保社区协同工作以标识出 5 种有前途的方法。此报告为每一种方式呈现了一些背景,同时带有关于该方法的成熟度的总结叙述,以及关于它为何有可能带来显著改变的理论基础,同时为每一种方法提供了延伸阅读。希望能有其他方法在未来被标识出来。

这些方法专注于具有 3~7 年视界的技术行为。关于改进软件的众多至关重要的方面并未被探讨,诸如创建更好的规范、使用今天可用的测试工具、理解并且控制依赖,以及创建并且遵守项目指导原则等。尽管这些领域位于此报告的范围以外,它们对于现在和未来都至关重要。类似地,此报告并未探讨作为对于软件和漏洞的更为宽泛的理解的一部分而必需的研发过程。诸如识别漏洞来源、漏洞如何表现为 bug,以及开发阶段的改进扫描等话题同样至关重要,但是它们同样不属于此报告的范围之内。

报告的这一章概述了前进所必需的一些步骤,通过雇佣更加广泛的社区,包括研究人员、资金提供者、开发者、经理和消费者/用户。本章解决了这些问题:1) 雇佣和支持研究社区,2) 教育和培训,以及 3) 授予软件的消费者和用户有意义地参与的权利,而非仅仅要求质量,而是推进它。

4.1 雇佣研究社区

除了简单地资助安全的软件的研究以外,还有众多方式以雇佣研究社区。

4.1.1 大挑战、奖金和奖励

众多组织机构曾经发起过大挑战,其中有些是普通的研究目标,而有些是竞赛。更加安全的软件可以作为挑战的焦点或者额外的好处,即竞赛可以专注于非安全性的目标,但是要求胜者生产安全的软件。例如,DARPA 网络安全大挑战的评分反映出了软件能够多么好地发现漏洞并且保护宿主 [DARPA16]。其他挑战可以专注于特定技术,诸如抽象释义、符号执行或者新编程语言的分析。众多组织机构利用 bug 赏金计划来为研究社区提供激励以查找并且通知组织机构有关 bug 的信息。

4.1.2 研究基础设施

存在若干种非常成功的与安全的软件相关的数据版本库,诸如美国国家漏洞数据库。然而还需要更多。可以有版本库用于分享相关研究成果,以及源代码的开放版本库,如 4.3.6 节所提到的。还需要关于弱点和 bug 的更好的理解。例如,多大比例的漏洞来源于实现错误,多大比例来源于设计错误?SPSQ 研讨会的参与者呼吁对于缺陷和弱点的更多深度理解。具体的问题包括对于关于漏洞的类型和流行度的经验数据的需求、编程和测试技术的有效性,以及“更加安全”的语言的好处和代价。新语言要求新的分析工具,以及在某些案例中还要求新的分析算法。强壮的研究基础设施还可以被用于研究可能影响软件质量的其他因素,包括管理实践、教育和培训、复杂度水平以及程序员过载。研究人员需要能够重现结果并且测试跨类型的代码。所有这些活动要求大型、公开的研究基础设施。

4.2 教育和培训

教育和培训的作用再怎么强调也不为过。开发者训练没有技术上的替代品。教育不仅仅是关于教会开发者如何编写更好的软件的,它还包括教育用户如何指定更好的软件,以及教育经理如何设置能够得到更高质量的软件的环境。

此外,教育和培训是将此报告中所讨论的技术方法从研究社区转移到开发社区和用户/消费者社区的首要机制。

对开发者社区的教育和培训需要应对当前教育体系中的后起之秀的开发者,也要应对需要提升其技能的当前开发者。

近两年来,高等教育的焦点已经转移到了更加强调一上来就内建安全性的软件设计,而非在其后添加安全性。K-12 教育也已经在网络安全努力中看到了成长——从用户和生产者的视角。很明确的是,计算机科学和网络安全共同成为安全编程的主题。理解网络安全的原理对于确保软件安全可用至关重要。越来越多的学术计划正在教育它们的学生在编程时脑子里始终记住安全性。

当前的开发者需要暴露于新方法和新技术之中。为了使得开发者作出改变,他们需要看到关于新方法和新技术有效的证据,以及培训素材。为了补充前线软件开发者的培训,经理和管理层也必须被教育,关于软件漏洞的风险管理启示,以及在网络安全和低漏洞软件领域进行投资的重要性。为了使得这种培训获得成功,还需要关于在安全的软件中的投资将会具有成本高效性的证据。

哪些教育学的技术最为有效这一点在当前尚不明确。早期研究显示了为开发者提供关于弱点的更好的理解可以创建更好的程序这一事实 [Wu11]。更多的研究以及从应用案例到指南教程的培训素材对于成功的过渡是必需的。美国联邦政府可以以身作则培训它自己的开发者社区。

美国国家网络安全教育倡议(NICE)的战略计划 [Plan16] 列出了关于改进教育和培训的 3 个目标。

加速学习和技能开发:启发公众和私人领域的紧迫感以应对高技能网络安全工作人员的短缺是至关重要的。必需的步骤包括:

  • 刺激那些能够更加快速地增加合格网络安全工作人员供给的方法和技术的开发
  • 推广那些能够减少获取与有需求的工作岗位相关的知识、技能和能力所需的时间和成本的程序
  • 雇佣那些可用并且有意愿继续从事网络安全工作的离职人员或者待业个人
  • 试验利用学徒身份和合作教育计划以提供一支立即可用的劳动力的方式,他们在挣得工资的同时还能学会必需的技能,以及
  • 探索方法以识别网络安全技能中的鸿沟,并且唤起关于应对所识别出的劳动力需求的培训的意识

培养多样化的学习社区:需要强化跨生态系统的教育和培训以强调学习、测定其成果,以及使得网络安全劳动力多样化。必需的步骤包括:

  • 改进教育计划、课程联合经验和培训,以及认证
  • 鼓励那些能够有效测定和验证个人天赋、知识、技能和能力的工具和技术
  • 在小学阶段启发学生的网络安全职业生涯意识,在初中阶段刺激网络安全职业生涯探索,在高中阶段使其为网络安全职业生涯做好准备
  • 增加创新性和高效的努力以增加女性、少数民族、退伍军人、残疾人以及其他未获充分代表的群体在网络安全领域中的劳动力数量,以及
  • 辅助关于网络安全职业生涯的学术通道的开发和传播

引导职业生涯开发和劳动力计划:雇员需要帮助以应对市场需求并且加强征募、招聘、开发以及留住网络安全天才。必需的步骤包括:

  • 识别并且分析那些支持呈现现在和未来的对于合格网络安全工作人员的需求和供给的数据来源
  • 发布并且唤起对于美国国家网络安全劳动力框架的意识,并且鼓励其采用
  • 辅助各州和区域联盟以识别网络安全通道,以应对本地劳动力需求
  • 提升辅助人力资源专业人士和招聘经理的工具以用于征募、招聘、开发以及留住网络安全专业人士,以及
  • 开展国际合作以分享网络安全职业生涯发展和劳动力计划的最佳实践

4.3 由消费者实现的技术转让

更好的软件的驱动因素之一在于软件的用户、消费者和购买者是否要求它。尽管用户社区明确地想要高质量的软件,他们很难有意义地要求它以及知道他们是否已经得到了它,并且因此发出关于开发低漏洞软件的信号。市场的需求促进了以消费者为中心的措施,以及其他政策和经济方式。一项措施为了能够显著地向消费者提供信息,它需要普遍性、可理解性、简洁性和高效性。一个范例是美国国家公路交通安全管理局(NHTSA)的 5 星安全评级。一旦评级持续出现在新车上,1 星和 2 星的车辆迅速变得稀少 [Rice08]。政策和经济方式超出了此报告的范围,但是它们对于用于改进的软件的成功技术转让至关重要。本节概述了于不同研讨会期间讨论过的一些方式。

4.3.1 合同和采购

美国联邦政府可以通过在合同和采购阶段要求软件质量以及更改一般预期来领导软件质量的显著改进。模型合同语言可以包括关于软件依附于更高的编码和担保标准的激励,或者关于对这些标准的拙劣的违反的惩罚性措施。用于网络安全和安全的软件的样本采购语言已经由防御社区 [Marien16]、金融部门、汽车行业和医疗领域发表。其评估必须包括提供“目的适用性”作为安全的软件的考虑因素。

4.3.2 责任

在软件社区中存在关于责任的大量讨论,包括在用于减少安全漏洞的软件测定和度量(SwMM-RSV)研讨会期间。众多参与者认为开发软件的企业应该为在软件送达之后发现的漏洞负有合同上的责任。很多人并不认为此时应该有法律上的责任。另一方面,这样的责任条款的语言应该足够严格,以使得如同某位参与者所写道的那样“使得企业对马虎的以及容易避免的错误和瑕疵负责”。

定义“马虎的以及容易避免的”并不是一件平凡的事。使其更加复杂的另一个因素是,责任涉及谁应该为之负责的概念。对于“开源”或者可免费获得的软件的案例,责任可能难于界定。

4.3.3 保险

随着网络的重要性持续增长,网络保险成为了一个增长的领域。针对关键基础设施保护和美国国土安全的金融服务部门协调委员会(FSSCC)编写了一部 26 页的文档,其标题为“网络保险产品购买者指南”,它定义了这种保险是什么、解释了为何组织机构需要它、描述了它可以被如何采购,以及给出其他有用信息。

4.3.4 厂商——消费者关系

如果软件拥有一份“物料清单”以使得使用它的人可以对新的威胁作出响应,在此,软件中的某些部分成为了攻击向量,那么将会有助于最终用户。用户有时被软件许可证禁止发布评估或者同其他工具的比较。乔治城大学最近发布了一项关于此问题的研究 [Klass16]。此研究受到美国国土安全部(DHS)科技理事会(S&T)网络安全分部通过安全和软件工程研究中心(S2ERC)的赞助。

4.3.5 标准

标准和指导原则的开发和采用,以及一致性评估程序被跨越多个行业应用以应对质量问题。美国志愿者业界共识标准系统允许巨大的灵活性以应对需求。在某些案例中,美国政府(联邦、各州和地方)设置行政法规标准和社区自律。例如,电气电子工程师学会(IEEE)于 2015 年发布了医疗器械软件安全的构建代码 [Haigh15] 并且发起了一项努力以便为能源和电力分配系统开发一份类似的最佳实践文档 [Landwehr15]。另一个范例是 NIST 的 用于改进关键基础设施的网络安全性的框架 [Framework14]。

4.3.6 测试和代码版本库

我们在 2.1 和 2.4 节解释了经过良好测试的代码的额外版本库的好处。软件的深度测试是困难并且耗时的,但是对于普遍使用的关键模块而言是必要的。SPSQ 研讨会的参与者指出了政府和基于社区的努力在测试关键软件中的价值。代码版本库提升了代码的重复使用并且鼓励组织机构通过提供结果可以被发表的位置来测试代码。版本库可以连同代码一起存储某些担保级别测定结果,或者甚至拥有内建的代码测定工具。版本库还可以包含具有低 bug 密度的项目的范例,诸如 Tokeneer [Barnes06]。

4.3.7 威胁分析

威胁分析,有时称为“威胁模型分析”或者“风险分析”,是一种评估风险或者威胁的方式 [Fundamental08]。通过威胁分析,软件可以被设计为避免引入某些漏洞并且降低其他漏洞的严重性。例如,一种形式的威胁分析是通过文档记录攻击面以理解对手可能如何利用接口以提升权限。威胁分析最好同时在架构和设计层级执行,如若不然,软件可能包含原本可以避免的漏洞 [Shostack14]。架构威胁分析可以显著增加软件的架构及其高级设计的安全强壮性和弹性,以显著降低漏洞的数量和严重性 [Diamant11]。

4.4 结论

对于显著减少软件漏洞的诉求发出自多个来源,包括 2016 年的美国国家网络安全行动计划。此报告识别了 5 种方法以实现此目标。每一种方法满足以下 3 个判据:1) 拥有显著改进软件质量的潜力,2) 能够在 3~7 年的时间框架内带来显著改变,以及 3) 是技术行为。被识别出来的方法应用了多种策略:

  • 在漏洞发生之前阻止它们,包括用于指定和构建软件的改进的方法
  • 查找漏洞,包括更好的测试技术以及对于多种测试方法的更有效的利用,以及
  • 通过构建更具弹性的架构来降低漏洞的影响,使得漏洞不能被有意义地利用

形式化方法:形式化方法包括多种基于数学和逻辑的技术,其范围从语法分析、类型检查、正确性证明、基于模型的开发,到自动建构校正。尽管之前被认为是过于耗时的,形式化方法已经在众多幕后应用中成为主流,并且在构建更好的软件以及支持更好的测试方面展示出了巨大的前途。

系统层级安全性:系统层级安全性降低漏洞的影响。操作系统容器和微服务已经成为美国国家信息基础设施的重要组成部分。鉴于使用它们所带来的明显的可管理性、成本和性能方面的优势,有理由预计它们的应用将会继续增长。这些技术的安全增强的版本一经采用,即可对整个美国国家信息基础设施中的软件漏洞利用产生广泛的抑制效果。

附加软件分析:有众多类型的软件分析——有些是通用的,有些针对非常特定的漏洞。附加软件分析的目的是能够将多种工具用作生态系统的一部分。这将会增加特定的软件分析工具的使用,以及在工具和技术之间获得协同作用的能力。

更多成熟的领域特定软件开发框架:此方法的目标是提升经过良好测试和良好分析的代码的使用(和重复使用),并且因此减少可被利用的漏洞的发生几率。

移动目标防御(MTD)和自动软件多样性:此方法是一系列技术的集合以改变软件的细节结构和属性,以使得攻击者在利用任何漏洞时的难度大大增加。自动软件多样性和 MTD 的目的是降低攻击者利用软件中的任何漏洞的能力,而非降低软件中的弱点的数量。

关于改进安全性的一项关键需求是使得软件拥有更少并且更加难于利用的漏洞。我们所描述的测定、技术和方法将会能够做到这一点。然而,高质量软件并不会被完全独立地创建出来。必须有强壮的研究基础设施、教育和培训,以及消费者需求。高质量软件是一个必要的步骤,但是还不够。跨越整个系统的生命周期的强壮的操作和维护过程仍然是必需的。

4.5 首字母缩略词列表

  • ACM:美国计算机协会
  • AI:人工智能
  • API:应用程序接口
  • ASLR:地址空间配置随机加载
  • AST:抽象语法树
  • BLP:Bell-LaPadula
  • BSIMM:在成熟度模型中构建安全性
  • CAP:网络安全担保计划
  • CEGAR:由反例指导的抽象详细化
  • CII:核心基础设施倡议
  • CIL:通用中间语言
  • CISQ:信息科技软件质量联盟
  • CMU:卡内基梅隆大学
  • CPU:中央处理器
  • CWE:通用缺陷列表
  • DARPA:美国国防高级研究计划局
  • DHS:美国国土安全部
  • DoD:美国国防部
  • DSL:领域特定语言
  • ESAPI:企业安全性应用程序接口
  • FAA:美国联邦航空管理局
  • FSSCC:金融服务部门协调委员会
  • GNU:Gnu’s Not Unix
  • GPU:图形处理器
  • GUI:图形用户界面
  • ICT:信息及通信技术
  • IDE:集成开发环境
  • IEEE:电气电子工程师学会
  • iFACTS:临时未来领域控制工具支持
  • I/O:输入/输出
  • IoC:控制反转
  • IR:中间表示
  • ISO:国际标准化组织
  • ITS:入侵容忍系统
  • KDM:知识发现元模型
  • LoC:代码行数
  • ML:元语言
  • MTD:移动目标防御
  • NaN:非数
  • NATS:英国国家航空交通服务控股公司
  • NHTSA:美国国家公路交通安全管理局
  • NICE:美国国家网络安全教育倡议
  • NICTA:澳大利亚国家信息及通信技术卓越研究中心
  • NIST:美国国家标准技术研究所
  • NITRD:网络和信息科技研发
  • OBDD:有序二元决策图
  • OS:操作系统
  • OSTP:美国白宫科技政策办公室
  • OWASP:开放式网络应用程序安全项目
  • SAFES:软件担保发现表达纲要
  • SAL:源代码注释语言
  • SAT:布尔可满足性问题
  • S2ERC:安全和软件工程研究中心
  • SI:国际单位制
  • SMT:可满足性模数理论
  • SPSQ:软件生产力、可持续性和质量
  • SSCA:软件和供应链担保
  • S&T:科技
  • TCSEC:可信计算机安全性评估判据
  • TOIF:工具输出整合框架

第 5 章 参考文献

OSZAR »