使您的软件运行起来: 确保软件是安全的【转】

(转自:https://blog.csdn.net/hmsiwtv/article/details/8123428

如今计算机安全性的最大问题之一是软件通常不够健壮。软件故障会有灾难性的现实后果,其中包括企业财政状况上的大红标记。

安全性只是能够引起重大财政危害的软件故障中的一个方面 ― 在日益加速的因特网电子商业世界里尤其如此。其它的软件故障包括可靠性和保险问题。软件在某些情况下使人们失去谋生的职业,甚至失去生命;不够安全的软件导致大公司的衰落或者消亡只是时间问题。

每个人似乎都知道或察觉到这些问题的存在,但知道如何克服它们的人很少。没有多少资源可用来指导开发人员如何编写安全的代码。更糟的是,如今许多软件是以难以置信的速度并且是在极大的市场压力下开发的。在这种市场压力下首当其冲受到损害的通常是软件质量(任何种类的质量)。在最好的情况下安全性往往也只是事后的想法,而通常它都被完全遗忘。

那不只是悲剧,还会造成灾难。

对安全性采取主动方法

对安全性进行改进永远是错误的解决方案。相反,应该从一开始就将安全性设计到软件中。在 Reliable Software Technologies,我们开发了一个已经在安全性咨询、代码开发和代码安全性分析中成功使用了多年的针对安全性的软件确保方法。这一方法已经在现实经验中多次证明了它的实用性 ― 尽管不能保证它能用最少的工作解决您所有的问题。

安全性是复杂的领域,开发安全的应用程序也不例外。我们的方法的主要目的是帮助开发人员避免针对安全性的事先无准备的“插入修补”方法,即当开发人员意识到错误时才进行修补,否则安全性不是考虑事项。(在以前的 “使您的软件运行起来”专栏文章中,我们讨论了这种方法的许多缺点。)

我们的方法有五个步骤:

  1. 设计系统时要有安全性观念。
  2. 根据已知和预期的风险分析系统。
  3. 根据严重性划分风险等级。
  4. 进行风险测试。
  5. 从设计过程开始对破坏的系统重复以上步骤。

我们的方法与“插入修补”方法之间存在着细微但重要的区别:我们的方法鼓励您在骇客(cracker)有机会测试和发现安全性漏洞之前就针对安全性测试并修正软件。然而,即使我们那样做了,我们仍然在进行某种插入修补。真正的区别在于我们尽力在软件发行以前进行所有的插入修补。在这种提前消除错误的尝试中,我们的方法要求开发人员接受过有关所有潜在安全性风险的良好教育。另外,它还非常依赖于良好的软件工程技术。

这当然很好,但是也存在一个重要的共性。我们的方法的所有五个特性之间的共同点是它们任何一个都不是轻而易举的。要最有效地使用这一方法,关键是要让自己了解所有重要的计算机领域事件。

回页首

为什么应该为安全性而设计

与事先无准备的安全性开发技术(往往工作得不是很好)相反,应该在开发周期的所有阶段中考虑安全性,而不是事后想到它时再补救。在现有系统上改进安全性完全是一个坏的主意。安全性并不是一个随时都可以添加到系统中的基本功能部件。安全性就象容错;它是一个需要有效、仔细地规划和设计的遍布于整个系统的特性。

编写安全的软件的更好方法是从一开始就将安全性设计到系统中。我们从许多系统的例子中体会到这一点,最初设计这些系统时并没有考虑安全性,但后来添加了安全性功能部件。许多这种系统都是安全性的“恶梦”。

Windows 95 和 Windows 98 平台就是一个这样的例子,它因许多安全性弱点而声名狼藉。人们普遍认为在行的攻击者可以使网络上任何 Windows 9x 机器崩溃或被黑掉。例如,Windows 9x 中的认证机制很容易被挫败。最大的问题是任何人都可以坐在 Windows 9x 机器旁,关机然后重新开机,不用密码登录,从而完全控制了这台计算机。简而言之,Windows 操作系统不是为今天的网络环境设计的;它是在 PC 还没有联网时设计的。Microsoft 试图改进它的操作系统以对这种新类型的计算机使用提供安全性,但是不太成功。

UNIX 由大学研究人员开发并使用,在设计时也没有考虑安全性。它的目的就是作为供团队成员组之间共享研究成果的平台。因为这一点,它还是经受了无数次修补和安全性改进;和 Microsoft 一样,这些努力并不太成功。

我们已经看到,许多现实中的系统(设计用来在受保护的专用网络中使用),为了在因特网中使用正在做类似的返工。在每一个案例中,因特网特定风险导致这些系统失去所有的安全性特性。

有些人把这称为环境问题,即系统在一个环境中足够安全而在另一个环境中则完全不安全。随着世界通过因特网互相连接得更加紧密,大多数机器所必须身处的环境有时却不太友好。

从头为安全性而设计总是比将安全性添加到现有设计要好。重用是值得赞扬的目标,但系统所处的环境对于安全性是如此密切相关以至于任何环境的改变都可能引起各种麻烦 ― 麻烦是如此之多,以至于以前经过充分测试和理解的工作都需要重做。

安全性对于软件开发人员来说应该有较高的优先级,因为对于您和您的客户来说,它是关系到信任,并最终关系到业务稳定性的问题。

回页首

如何评估安全性风险

在应用程序的功能性与安全性之间有一个基本的权衡。通常,您根本不能确定您的系统是否完全安全。一个常见的笑话说的是世界上最安全的计算机是埋在用混凝土填充的 10 英尺深的洞里的那一台。使用这样一台机器时,自求多福吧!对于现实中的系统,安全性问题归结为特定的企业为了有效地解决即将到来的问题愿意冒多大的风险。安全性事实上是风险管理的问题。

风险管理的第一步是评估风险:识别潜在的风险、发生这些风险的可能性以及它们可能达到的严重程度。

有效的风险评估需要专业的安全性知识。评估员必须能够识别已知的攻击可能会应用到身边系统的何处,因为很少有完全独特的攻击会暴露自己。不幸的是,很难取得这样的专业知识。软件安全性是一个大问题,不是在一篇文章中用几句话就可以说清楚的。(我们希望本篇专栏能及时帮助解决那个问题。)

当您有详细的系统规范可以着手工作时,风险识别会有最大效果。如果有权威的资源可以告诉您系统在特定环境下的表现将如何,其价值无法估量。当规范在开发人员的脑子里而不在纸上时,整个过程变得更模糊。很可能您在脑海中搜寻两次需求信息并得到矛盾的信息而浑然不知。

一旦识别出风险,下一步就是按严重性给它们划分等级。风险的相对严重性非常依赖于身边系统的需要和目标。于是,在这一步骤中,参考详细的需求文档是有帮助的。有些风险可能根本不值得减轻,因为风险的级别很小,或成功攻击的负面影响无需过多关注。

风险评估是确定如何分配测试和分析资源的关键。因为资源分配是业务问题,所以拥有可靠的数据有助于确保做出与资源分配有关的好的业务决定。

回页首

开发和划分安全性需求

我们已经暗示了好的软件工程实践对于任何可靠的安全性方法都很重要。任何依照经过充分理解和完全文档化的需求而设计的系统将比用口香糖和固定铁丝勉强修补的系统要好得多。

您应该确保精心构造您的需求。例如,需求“该应用程序应该尽可能地使用密码术”不是个好的需求,因为它甚至还没有诊断问题就规定了解决方案。需求文档应该表达的不仅是系统必须做什么和禁止做什么,还有系统为什么要按描述的运行。在这个示例中,更好的需求可能是“信用卡号是敏感信息,应该保护它们防止可能的窃听”。选择如何保护该信息 ― 密码术或某种其它手段 ― 应该推迟到系统有了规范之后再进行。

我们推荐为您的组织创建标准安全性指南的模板或文档,这样您就可以从中为任一特定项目派生与安全性相关的需求。这样的文档允许个别的应用程序有个别的需要,并且不同的安全性侧重点有不同的优先级,同时提供一个框架允许跨应用程序进行一致性分析。例如,“拒绝服务”对于客户机应用程序可能不是重要的关注对象,因为只有客户机受到影响。但是对于商业 Web 服务器进行的拒绝服务攻击可能会同时拒绝对成千上万人的服务。

这样的指南通常既包含有关如何执行安全性分析的概要解释,又包含应用程序开发人员应该确保考虑的风险列表。当然,开发人员不应该期望这样的列表是完整的。但是开发人员可以期望同一组织内的其他应用程序开发人员将会考虑同样的一组风险。

系统规范通常是由一组需求创建。可靠的系统规范的重要性不能被过分强调。毕竟,没有规范,系统运行不可能是错误,它只可能是令人惊讶!特别是在运行商业系统时,没有人希望安全性意外。

可靠的规范还可以描绘出一个关于系统做什么以及为什么这样做的连贯的全景图。规范应该尽可能的正式,但不要变得晦涩难解。请记住规范的存在目的是为了理解系统。通常,规范越清楚并且越容易理解,产生的系统也越好。

回页首

外部分析的重要性

没人会故意构建一个不好的系统。开发人员是骄傲的,并且他们一般都努力工作以创建可靠的工作系统。这正是安全性风险分析小组不应包含任何来自设计和开发小组成员的原因所在。安全性测试与标准测试不同的基本方式在于摆脱设计的影响并对系统保持完全独立的见解的重要性。如果开发人员担当作为安全性测试员的额外职责,那么麻烦很可能会发生。设计人员和开发人员通常与他们的系统太接近,并对他们的系统可能有缺陷表示怀疑。

因此,更好的方法是请一个外部小组进行安全性分析和测试(通常称为“内部安全调查组”)。这样做的额外好处是可以测试系统设计文档的完整性,因为一个好的内部安全调查组会在他们的分析中大量地运用那些文档。当然,在进行那样的分析以前,设计小组必须确保需求和程序的规范足够清楚,以便外部小组能完全理解这一系统。

经验丰富的外部分析员小组在分析过程中会考虑许多不同的方案。经常考虑的方案示例包括反编译风险、窃听攻击、回放攻击和拒绝服务攻击。测试在有指导而不是随机地进行时最有效。考虑可能如何将这些方案应用到您的系统上可以产生极其相关的安全性测试。

选择外部安全性分析小组的另一个好的理由:即使最好的开发人员也往往缺乏有效地进行这种分析所必需的安全性专业技术。当然,最好的结果一般将通过组成一个高薪聘请的外部安全性专家小组才能获得。谢天谢地,这样的小组往往不是必需的;从您自己的组织选出具有良好的安全性知识并且没有参与设计决定的人组成一个小组就足够了。不幸的是,安全性专业技术如今似乎成了稀有商品。确定是否寻求组织以外的帮助应该基于风险分析来决定:您掌握的资源能降低足够的风险吗?

安全性测试对比功能测试

对系统的潜在风险进行等级划分后,就可以进行安全性测试,尽管这有些困难。测试是一个完全凭经验的活动,需要一个实际运行的系统并需要对该系统进行仔细的观察。安全性测试通常不会产生不言而喻的结果,如明显的系统插入。更常见的是系统将以奇怪或古怪的方式运行,这就向分析员暗示有趣的事情正要发生。可以通过对代码的手工检查进一步探究这类疑惑。例如,如果分析员通过提供非常长的输入使程序崩溃,那么可能存在缓冲区溢出 ― 并可能演变成为安全性缺口。下一步就是通过查看源代码找出程序在哪里崩溃以及为什么崩溃。

功能测试包括动态地探测系统以确定系统在正常环境下是否如预期地运行。安全性测试就不同了(当做得不错时)。

安全性测试应该包括以攻击者可能探测的方式探测系统,寻找软件中可以被利用的弱点。安全性测试在由风险分析阶段发现的系统风险指导时最有效。这意味着安全性测试基本上是一种创造性的测试形式,它只和它所基于的风险分析一样有力。安全性测试天生就被已识别的风险和测试人员的安全性专业知识限制。

实践证明,代码覆盖范围是理解一组特别的测试能发现多少系统缺陷的优秀度量标准。使用代码覆盖范围作为功能测试有效性的度量标准一直是个好主意。对于安全性测试,代码覆盖范围扮演了更关键的角色。简而言之,如果程序的某个区域(功能方面或安全性方面)在测试阶段从没有被实践过,应该马上怀疑该区域是否有安全性问题。一个明显的风险是未经实践的代码将包含特洛伊木马弱点,表面上无害的代码会由此执行攻击。不太明显(但更普遍)的风险是未经实践的代码含有严重的错误,这些错误可以演变成为一次成功的攻击。

动态测试与静态测试的比较

动态安全性测试有助于确保这样的风险不会回过头攻击您。静态分析同样有用。当今很多安全性问题是已被充分理解的问题的重复,它们还会回来。1998 年超过百分之五十的 CERT 警告涉及缓冲区溢出问题的事实强调了这一点。如今怀疑所有代码都有缓冲区溢出问题是没有理由的,但是缓冲区溢出问题仍然是最大的源代码安全性风险。

有可能静态地扫描安全性至关重要的源代码以发现已知问题,并修改遇到的所有问题。许多黑客(hacker)都有代码扫描工具,这些工具可以从头到尾扫描您的代码来发现潜在的问题,然后他们会亲自检查以确定是否的确存在安全性问题。阻止这种方法的关键是对潜在问题具有渊博的知识。这样的一些工具对于降低进入安全性分析领域的门槛是一个好的起步,因为这些工具将只对存在于安全性专家头脑中的知识进行编码,而且它们这样做的方式对于所有的开发人员都会是得益的。因此开发人员自己将这样的工具当作公平的第三方评估人员使用是合理的。

回页首

结束语

软件如今必须以无数种方式运行。好的软件确保实践有助于确保软件正确地运行。保险至关重要和高确保的系统在分析和追踪软件行为方面始终进行着极大的努力。安全性至关重要的系统必须跟着做。只有我们把安全性看作极其重要、复杂和完整的系统属性,而不是简单的功能部件或事后的补救措施,我们才能避免对安全性采用象绷带似的插入修补方法。

计算机安全性日益重要,因为世界正变得高度互联并且网络正在被用来执行关键的事务。决定将本地网络连接到因特网是一个安全性至关重要的决定。机器赖以生存的环境近年来已发生了根本变化,而软件安全性必须比以前更好地预见这些风险。

出现意外故障的软件是大多数安全性问题的根源。尽管软件确保还有待完善,但它会给那些想直击潜在安全性问题要害的从业者巨大的收获

猜你喜欢

转载自blog.csdn.net/biqioso/article/details/81113188
今日推荐