威胁建模:安全设计中的风险识别和规避
上QQ阅读APP看书,第一时间看更新

0.1 威胁建模

首先,我们概述威胁建模的概念、它为什么有用以及如何适应开发生命周期和总体安全性计划。

0.1.1 什么是威胁建模

威胁建模是通过分析系统来发现那些由于不太完善的设计方式所导致的缺陷的过程。它的目标是在将这些缺陷(由于实施或部署)引入系统之前就确定它们,以便尽早采取修正措施。威胁建模活动是一项概念性练习,旨在帮助你了解应该修改系统设计的哪些特征,以将系统中的风险降低到其所有者、使用者和操作员可接受的水平。

在进行威胁建模时,你可以将系统看作一个由其组件、与之交互的外部世界(如其他系统)以及可能在系统上执行操作的行为者的集合。进而,你要尝试想象这些组件和交互在什么情况下可能会运行失败。在这个过程中,你将确定系统面临的威胁,从而更改和修改系统,使得系统可以抵抗潜在的威胁。

威胁建模是一项周期性的活动。它以明确的目标开始,以分析和行动继续,然后重复。它不是灵丹妙药,并不能解决所有的安全问题。它也不是按钮式工具,不会像扫描器一样指向你的网站或代码库,生成一个待打钩的项目清单。威胁建模是一个逻辑上的智力过程,如果你让团队中的大多数人(即使不是全部)参与其中,效果将非常明显。它会引起讨论,并使你的设计和执行更加清晰。所有这些都需要工作经验和一定量的专业知识。

威胁建模的第一条规则可能是垃圾进,垃圾出(GIGO)[1]。如果将威胁建模作为团队工具箱的一部分并让所有人积极参与,你将获得很多好处。但是如果你没有全心全意地参与其中,没有完全了解它的优缺点,或将其作为合规性的“勾选”项目,那只会浪费时间。一旦找到了适合的方法,并付出努力,系统的整体安全性就会大大提高。

0.1.2 为什么需要威胁建模

威胁建模能促使形成更清晰的架构、定义明确的信任边界(你尚不知道这些信任边界是什么以及为什么它们很重要,但是很快你就会明白!)、进行有针对性的安全测试以及形成更好的文档。从长远来看,这将使你的工作变得更轻松、更好。最重要的是,它能提高你和你的团队的安全意识,从而在整个开发工作中带来更好的安全标准和指导方针。

上述好处都很重要,但更重要的是,了解系统中可能出现的问题以及如何解决它们,将增加你对所交付物的信任,使你可以自由地专注于系统的其他方面。

0.1.3 障碍

程序员的问题在于,你永远不知道他在做什么,直到为时已晚。

——Seymour R. Cray, Cray line of supercomputers公司创始人

这句话到今天仍然适用。给开发人员一份规范或一组合理且文档化良好的需求,然后退后一步,可能会发生许多有趣的事情。

老实说,我们知道开发团队拥有可以承受高要求的、负责任的出色人才。他们必须应对几乎不断变化的学习环境,精通所学,把握全局。向这些人才施加“不了解某些真正基础且重要的安全事项”方面的压力是不公平的。考虑到合规性、达成业务目标等指标,在实际交付有效、有用的内容方面还有很大的改进空间,开发团队可以将这些内容转化为知识和实际用途。

安全专业人员的任务之一是对开发社区进行安全教育,包括如何实现安全系统,以及事后如何评估代码和系统的安全性。依靠一套昂贵的工具集来补充(并在很大程度上隐藏)组织的安全专业知识似乎更容易。挑战在于,工具内置的专业知识通常对于用户而言是隐藏的。如果检测方法对他们透明,那么开发团队将大为受益。这里有些例子:

·基于计算机的培训(Computer-Based Training,CBT)对于每位新员工来说都是一场灾难。听别人读45分钟的幻灯片,想想都无聊透顶。

·过度依赖扫描器和静态代码分析器等所谓的“灵丹妙药”。它们承诺使用人工智能、机器学习、污点分析、攻击树甚至“万能的天神”,但未能始终如一地产生相同的结果,或者误报的概率很高。此外,分析工具希望整个系统在运行扫描之前就已经存在,更不用说在开发过程中占用很长的时间了,这与持续集成/持续开发(CI/CD)的价值相悖。

·咨询服务。根据要求,安全从业人员会介入,执行补救工作(或“定向培训”),然后消失(我们称之为海鸥咨询——它们向你飞来,啄你,然后飞走),留给团队“一地鸡毛”。依靠安全从业人员会带来重大不利影响:他们不属于团队,带着偏见指手画脚,所作所为几乎毫无帮助。货物崇拜[2]行为随之而来,因为团队试图不断复制安全从业人员留下的结果子集。

我们的安全专家还对组织内部的开发者期望产生了错误的认识:

·组织可以通过购买的方式形成强大的安全态势。如果它在工具上投入足够的资金,将解决所有的安全问题。

·每季度30分钟的强制性培训足以使组织通过审计。这30分钟足以让开发团队的成员了解他们的期望。由于开发团队的成员可以访问优质的培训内容,因此他们使用的昂贵工具只会小心地证实他们确实安全地完成了工作。

自2019年年中以来,“左移”的想法在安全行业蔚然成风。想象一下你从左到右阅读的工作流程。工作流的开始在左侧。当我们说“左移”时,是指希望安全流程尽可能向“左”移动,直到开发工作流程的开始(无论使用哪种开发方法)。这允许安全事件发生并尽早处理。与设计密切相关的威胁建模等活动应该在系统生命周期中尽早发生。而且,如果还没有发生,那就应该立即发生。

我们不赞成“左移”现象,而是倾向于使用从设计开始的方法论,或者更早地从左开始,以需求作为系统安全性的基础。

随着过程的改变,线性的“从左到右”的开发周期变得不那么明显,左移可能无法满足系统中的所有安全需求。相反,在考虑系统之前,安全社区将需要进一步转移到开发人员和设计人员的生活中。在那里,我们将需要集中精力培训开发团队,以做出安全的选择,并提高能力,以从根本上避免威胁。

具体实施时,安全性应该由行业的集体培训工作向左转移,并通过安全代码在语义和逻辑上表示。但是,如果培训未能达到期望,那么有哪些纠正措施可用于修正失败的假设?

让我们从另一个角度来看问题,然后将各个部分连接起来,对这一疑问做出连贯的回应(邀请参加讨伐!)。在讨论安全策略时,有些人谈到“摆在桌面上”。安全团队和管理人员希望“利益相关者”在“正在进行的讨论”中为安全保留“一席之地”。这使他们有理由证明自己需要使用那部分资源。但是,还有另一个重要资源未被认可,因为它被“广泛的培训”和所谓的“灵丹妙药”所迷惑。而资源就是开发者的时间和关注度。

让我们考虑一个Web开发者。无数的模因反映了这样一个事实:如果今天一个Web开发者在早餐前学习了有关LAMP堆栈[3]的所有知识,那么午餐后这些知识就变得毫无用处了,因为整个行业都将转移到MEAN堆栈[4]上。MEAN堆栈将在喝完两杯拿铁之后被另一个新事物取代,直到它再次出现在我们刚刚开始的新的、改进的(并且完全不向后兼容!)版本中。每一个新堆栈都带来了一组新的安全挑战以及与安全相关的习惯用法和机制,必须理解和整合这些习惯用法和机制,才能有效地保护正在开发的系统。当然,每个堆栈都需要一个独特的安全合约,Web开发者必须快速学习并熟练掌握这份安全合约。

但是网站不能宕机,对它的管理应该在开发人员学习新工具时同步进行。

正如理查德·费曼(Richard Feynman)告诉我们的那样:“教的是原理,而不是公式。”在本书中,我们将着重于原理,以帮助你理解和思考什么是适合你的威胁模型,以及如何在特定情况下助力你的项目和团队。

0.1.4 系统开发生命周期中的威胁建模

威胁建模是在系统开发生命周期中执行的一项活动,对系统的安全性至关重要。如果没有以某种方式进行威胁建模,那么很可能会通过设计选择引入安全性故障,这些故障很容易被利用,以后很难修复(而且代价高昂[5])。遵循“内置而非附加”的安全原则,威胁建模不应被视为合规性的里程碑。在最重要的情况下未能执行此项活动会给现实世界带来严重的后果。

如今,大多数成功的公司都不再像几年前那样执行项目。例如,无服务器计算[6]等开发范例,或CI/CD[7]中的一些最新趋势和工具,对开发团队如何设计、实施和部署当今的系统都产生了深远的影响。

由于市场需求和竞争,如今,你很少有机会在开发系统之前坐下来查看完整的详细设计文档。产品团队首先将“最小可行产品”版本推向公众,并开始建立品牌和吸引用户。然后,产品团队依靠增量版本来添加功能并在出现问题时进行更改。这种做法导致在开发周期的后期对设计要进行重大更改。

现代系统具有前所未有的复杂性。你可能会使用许多第三方组件、库和框架来构建新软件,但这些组件很多时候都没有很好的文档记录,不容易理解且安全性很差。要创建“简单”系统,你需要依赖复杂的软件、服务和功能等层。同样,以无服务器部署为例,“我不在乎环境、库、机器或网络,我只关心功能”是短视的。幕后隐藏着多少机器?你对功能“下”的活动有多少控制权?这些因素如何影响系统的整体安全性?如何验证你使用的是最合适的角色和访问规则?

为了可靠地回答这些问题并立即获得结果,你可能会想求助外部安全专家。但是安全方面的专业知识可能会有所不同,而聘请专家的成本很高。一些专家专注于特定的技术或领域,另一些专家则涉猎广泛但不够深入。因此,我们建议在内部发展威胁建模知识,并使其尽可能适应团队。

开发安全系统

无论使用哪种开发方法,系统的开发方式都必须经过一些特定的阶段(见图0-1)。

·创意

·设计

·实施

·测试

·部署

图0-1:开发过程及相关的安全活动

例如,在瀑布方法中就遵循这些阶段。请注意,文档起着持续的作用——它必须与其他阶段并行发生才能真正有效。当使用这种方法时,很容易看到威胁模型在设计时提供了最大的好处。

我们将威胁建模与设计紧密联系在一起。这是为什么?

一个被广泛引用的概念[8]表明,问题越接近部署或部署后,解决问题的成本就会显著增加。对于熟悉制作和营销软件的人来说,这是显而易见的。将解决方案应用于开发中的系统要比已经部署在数千个(甚至数百万个)地方的系统便宜得多[9]。你不必承担某些用户未打补丁,或者给系统打补丁而导致无法向后兼容的责任。你不必与因某种原因而无法继续使用补丁的用户打交道,也不必承担支持长期且有时不稳定的升级过程的成本。

因此,威胁建模从本质上看是一种设计,并试图识别安全缺陷。例如,如果你的分析表明某种访问方式使用了硬编码的密码,则会将其识别为需要解决的问题。如果发现的问题仍未解决,那么你正在处理一个将在系统生命周期后期可能被利用的问题,这也称为漏洞,具有被利用的可能性以及被利用的相关成本。你可能无法发现问题,或者无法确定可以被利用的东西。完美和完整性不是此练习的目标。

威胁建模的主要目标是识别缺陷(可以解决的问题)而不是识别漏洞(可以利用的问题)。然后,你可以应用缓解措施来降低被利用的可能性和被利用的成本(即损害或影响)。

一旦确定一个缺陷,就可以减轻或纠正它。你可以通过应用适当的控件来做到这一点。例如,你可以创建一个动态的、用户定义的密码,而不是一个硬编码的密码。如果情况允许的话,你可以对该密码进行多次测试来确保密码强度。你也可以让用户决定密码策略。你还可以完全改变你的方法,并通过删除密码使用并支持WebAuthn[10]来完全消除该缺陷。在某些情况下,你做出的系统部署方式和使用硬编码密码等决定会有一定的风险。你必须确定风险是可以接受的,并记录发现的缺陷,识别和描述不解决它们的理由,并将其作为威胁模型的一部分。

威胁建模是一个演进的过程。首次分析时,你可能找不到系统中的所有缺陷。例如,也许你没有合适的资源或没有适当的利益相关者来检查系统。但是拥有初始威胁模型比没有威胁模型要好得多。并且,在威胁模型更新后,下一次迭代将变得更好,可以识别其他缺陷,并可以更准确地保证没有发现缺陷。你和你的团队将获得经验和信心,这将驱使你考虑新的、更复杂、更巧妙的攻击和方式,并且系统将不断完善。

不再使用瀑布模型

让我们继续讨论更现代的敏捷方法和CI/CD方法。

因为这些是开发和部署软件的较快方法,所以你可能会发现无法停止一切,启动适当的设计会话,并与需要发生的事情达成共识。有时,你的设计会根据客户的要求而演变,而有时,你的设计是从系统的持续开发中演变而来的。因此,可能很难预测整个系统的总体设计(甚至很难知道整个系统是什么)。并且,你可能无法事先进行大范围的设计修改。

从微软的“安全冲刺”提议,到每一次冲刺中迭代地对较小的系统单元应用威胁建模,许多设计提案都概述了在这种情况下如何进行威胁建模。而且,不幸的是,有人声称威胁建模“降低了敏捷团队的速度”。不影响敏捷团队速度但存在安全漏洞和降低敏捷团队的速度的同时降低了访问你的数据的黑客团队的速度,哪一个更好?目前,重要的是要认识到问题,以便将来提出可能的解决方案。

在设计过程中解决安全问题后,你将看到安全性如何影响开发的所有其他阶段。这将帮助你认识到威胁建模如何对系统的整体安全状况产生更大的影响,以下是总体衡量:

·系统内的当前安全状态。

·可供攻击者探索和利用的攻击向量、入侵点或改变系统行为的机会(也称为攻击面)。

·系统中现有的漏洞和缺陷(也称为安全债务)以及由这些因素导致的系统和业务的综合风险。

实施和测试

在开发过程中,实施和测试是安全性的最重要方面。归根结底,安全问题出现在代码编写过程中出现的问题或错误中。一些臭名昭著的安全性问题[比如心脏滴血(Heartbleed)漏洞]和大多数缓冲区溢出问题不是由不良设计引起的,而是由于代码未按预期执行或以意外方式执行。

当你查看漏洞的类别(例如,缓冲区溢出和注入问题)时,很容易看出开发者是如何无意中引入它们的。剪切和粘贴先前使用的代码很容易,但在考虑错误输入时也容易陷入“谁可能这样做?”的信念。或者,开发者可能会由于无知、时间限制或其他因素而简单地引入代码错误,而不考虑安全性。

一些工具可以通过执行静态分析来识别代码中的漏洞。另一些工具通过分析源代码来实现。其他人则通过模拟输入的方式运行代码以识别不良结果[此技术称为模糊(fuzzing)测试]。近期,机器学习成为一种识别“错误代码”的新型方法。

但是威胁建模会影响这些与代码相关的问题吗?答案是具体情况具体分析。如果你将系统作为一个整体来看,并确定能够通过解决根本缺陷来完全消除一整类漏洞,那么你在设计时就有机会解决与代码相关的问题。Google针对XSS(跨站脚本漏洞)以及其他类型的漏洞,在所有产品中使用解决以上漏洞的库和模式[11]。不幸的是,为解决某些类型的问题而做出的选择可能会切断解决其他问题的途径。例如,假设你正在对高性能和高可靠性有很高要求的系统上工作,可以选择使用提供直接内存控制和较少执行开销的语言(例如,C语言),而不是使用提供更好内存管理功能的Go或Java等语言。在这种情况下,通过更改技术栈,你可能只有有限的选择来影响需要解决潜在安全问题的范围。这意味着你必须使用开发时间工具和测试时间工具来管理结果。

文档和部署

随着系统的开发,负责它们的团队可能会经历一个自我发展过程。当一群人开始学习或理解某事物并保留相关知识而不进行记录时,就会存在“部落知识”或系统知识。但是,团队成员随着时间的推移会发生变化,随着个人离开团队和新成员加入,这种部落知识可能会丢失。

幸运的是,一个有据可查的威胁模型是一个很好的工具,可以为新团队成员提供正式的专有知识。许多模糊的数据点、验证说明和一般思考过程(例如,“你们为什么在这里这样做?!”)非常适合作为威胁模型中的文档留存下来。为克服限制而做出的任何决定及其对安全性的影响也适合记录下来。部署也是如此——威胁模型是一个参考第三方组件清单、保持最新版本、强化它们所需的工作以及配置它们时所做的假设的好地方。网络端口及其协议清单等简单信息不仅解释了数据在系统中的流动方式,而且还解释了有关主机身份验证、防火墙配置等部署决策。所有这些类型的信息都非常适合威胁模型,如果你需要响应合规审计和第三方审计,查找和提供相关详细信息将变得更加容易。