第2章 软件安全保障概念
2.1 软件工程
2.1.1 软件工程概述
随着计算机技术的不断发展,从20世纪60年代开始,软件逐渐作为一种产品被广泛地使用,出现了专职的应客户需求来编写软件的“软件作坊”,编写软件不再是为了实现开发者自身的功能需求。但这一时期,软件数量急剧膨胀,需求日益复杂,而软件的开发方法基本上依然沿用早期的个体化软件开发模式,从而造成软件项目开发成本过高、进度缓慢、不符合用户需求、软件质量低劣、可维护性差等严重问题,“软件危机”随之产生。
这些问题主要由两个原因造成:一是与软件自身的特点有关,二是与软件开发与维护的方法有关。
首先,由于软件缺乏“可见性”,在编写出程序代码并在计算机上运行之前,软件开发过程的进展情况较难衡量,软件的质量也较难评价,而且如果在软件运行过程中发现了错误,则很可能是在开发时期引入的,修改错误意味着修改软件设计,这就在客观上使得软件较难维护。
其次,随着计算机性能的不断提升,能够支持的软件规模也越来越庞大,从而使软件复杂性呈指数级上升。为了在预定时间内开发出软件,软件开发过程中的分工合作在所难免,然而,如何保证每个人完成的工作在集成后能形成一款高质量软件,是一个非常复杂的问题,这必须由科学的规划和管理来支撑。
鉴于人们在软件开发时所遭遇的困境,北大西洋公约组织在1968年举办了首届软件工程学术会议,并提出“软件工程”的概念来界定软件开发所需的相关知识。自“软件工程”被正式提出至今,在相关领域已累积了大量的研究成果,并进行了大量的技术实践,借由学术界和产业界的共同努力,软件工程已发展成为一门专业的学科。
软件工程是一门研究如何使用系统化、规范化、数量化等工程原则和方法去进行软件的开发和维护的学科。软件工程采用工程的概念、原理、技术和方法来开发维护软件,把经过时间考验而证明正确的管理方法和最先进的软件开发技术结合起来,应用到软件开发和维护过程中,来解决软件危机问题,生产出无故障的、及时交付的、在预算之内的和满足用户需求的软件。
如前所述,软件工程的基本目标是生产具有正确性、可用性及合算性的产品。其中,正确性和可用性可归结为软件质量,合算性可归结为软件开发成本。
IEEE将软件工程定义为:
(1)将系统化的、规范的、可度量的方法应用于软件的开发、运行和维护过程,即将工程化应用于软件;
(2)对(1)中所述方法的研究。
事实上,软件工程是应用计算机科学理论和技术,以及工程管理的原则和方法,实现满足用户需求的软件产品的定义、开发、发布和维护的工程活动。
软件工程活动是生产一个达到工程目标要求,能满足用户需求的软件产品的过程或步骤,包括需求、设计、实现、维护、确认/验证等活动。常用软件工程活动表如表2-1所示。
表2-1 常用软件工程活动表
2.1.2 软件工程基本原理
软件的工程原则主要围绕工程设计、工程支持和工程管理开展,软件工程通常遵循7条基本原理,它们是确保软件产品质量和开发效率的最小集合。
1.用分阶段的生命周期计划严格管理
在软件开发与维护的整个生命周期过程中,需要完成许多性质各异的工作,应该把软件生命周期分成若干阶段,并相应制定出切实可行的计划,然后严格按照计划对软件的开发和维护进行管理。在整个软件生命周期中应严格执行6类计划:项目概要计划、里程碑计划、项目控制计划、产品控制计划、验证计划和运行维护计划。
2.坚持进行阶段评审
在软件开发的不同阶段进行修改需要付出的代价是不同的,在早期进行变动,涉及内容较少,因而代价也较低;而在开发的中期,软件配置的许多工作已经完成,如果引入一个变动,则要对所有已完成的配置工作都进行相应的修改,不仅工作量大,而且逻辑上也更复杂,因此付出的代价剧增;在软件“已经完成”时再进行变动,则需要付出更高的代价。因此,在软件生命周期每个阶段都应进行严格的评审,以便尽早发现错误。
3.实行严格的产品控制
软件需求是软件开发的基础,不应随意更改。如果在软件开发过程中需要变更需求,则应采用科学的产品控制技术来实现,即采用变更控制,又叫基准配置管理。当需求变动时,其他各个阶段的文档或代码也应随之变动,以保证软件的一致性。
4.采用现代程序设计技术
从20世纪60~70年代的结构化软件开发技术,到最近的面向对象技术,从第一、第二代语言,到第四代语言,人们致力于研究各种新的程序设计技术,以及各种先进的软件开发与维护技术。因此,采用先进的技术既可以提高软件开发的效率,又可以降低软件维护的成本。
5.阶段成果应能量化
在物理形态上,软件是一种看不见、摸不着的产品。软件开发工作进展情况可见性差,难于准确度量,造成软件开发过程比一般产品的开发过程更难以评价和管理。为了更好地进行管理,应根据软件开发的总目标及完成期限,尽量明确规定开发小组的责任和产品标准,从而使所预期的成果能够被量化和审查。
6.开发小组的人员应少而精
开发人员的素质和数量是影响软件质量和开发效率的重要因素,开发人员应少而精。这一条基于两点原因:高素质开发人员的效率比低素质开发人员的效率要高几到几十倍,开发工作中犯的错误也要少得多;当开发小组为N人时,可能的通信信道为N(N-1)/2,可见随着人数N的增大,通信开销将急剧增大。
7.承认不断改进软件工程实践的必要性
遵从上述6条基本原理,就能够较好地实现软件的工程化生产。但是,它们只是对现有的经验的总结和归纳,并不能保证赶上技术不断发展的步伐。因此,应把承认不断改进软件工程实践的必要性作为软件工程的第七条原理。根据这条原理,不仅要积极采纳新的软件开发技术,还要注意不断总结经验,收集进度和消耗等数据,进行出错类型和问题报告统计。这些数据既可以用来评估新的软件技术的效果,又可以用来指明必须着重注意的问题和应该优先进行研究的工具和技术。
2.1.3 软件工程的特点
1.软件工程的科学性与艺术性
从20世纪50年代至今,软件工程经过了长期的积累,已经具备了相当的基础。人们认为软件工程正在进入职业化工程阶段,当然还远不成熟。所以软件工程的指导知识还是“艺术”、实践方法/原则和科学知识并立,软件工程行为既有科学性,又有实践性,还有艺术性。
科学性是运用范畴、定理、定律等思维形式反映现实世界各种现象的本质规律的知识体系。它重在把握事物的规律性,并按照这些固定的规律指导活动顺利和正确地进行。
艺术性则是那些在科学之外依赖于人类天性和创造性的知识。没有什么固定的规律可以保证艺术活动的顺利和正确进行。
虽然艺术活动没有什么固定的规律,但是人们在长期的实践活动中却可以发现和总结出一些经验,它们被称为实践方法或原则。实践方法和原则不能保证艺术活动的顺利和正确进行,但可以在一定程度上指导艺术活动更好、更快地进行,提高相对的成功率。
指导软件工程的科学知识主要是计算机科学,它建立了软件生产的知识基础,如软件开发的理论、方法、技术、模型等。这是软件工程学习的重点。
软件工程也积累了很多有效的实践方法与原则,既包括配置管理、风险控制、需求管理等管理办法,又包括模块化、信息隐藏、设计原则等技术原则。这也是软件工程学习的一个重点。
在少数工作上,软件工程还依然需要依赖个人的才能,即“艺术性”,这在软件分析与设计活动中尤为突出。
2.软件工程的成本效益
软件工程以成本效益为生产成功的基本条件。成本是软件开发的耗费,效益是客户为了得到软件产品愿意付出的费用。
在实践中,能够满足成本效益的软件生产方案可能不止一个,这些方案都是有效的,都是可以采用的,不需要再分辨最好的方案。也就是说,软件工程不追求最好的软件产品,只要求足够好的软件产品。
2.1.4 软件生命周期及生命周期模型
1.软件生命周期
一个软件从定义、开发、使用和维护,直到最终被废弃,要经历一个漫长的过程,通常把软件经历的这个漫长的过程称为软件生命周期。软件生命周期主要是为了解决什么人(who),在什么时候(when),做什么事(what)及怎样做(how)这些事,以实现软件的预期目标。
软件生命周期通常包括问题定义、需求分析、软件设计、软件编码、软件测试、运行维护等阶段,这种按时间分程的思想是软件工程中的一种思想原则,即按部就班、逐步推进,每个阶段都要有定义、工作、审查、形成文档以供交流或备查,以提高软件的质量。
软件生命周期的每一个阶段都有确定的任务,并产生一定规格的文档,提交给下一个周期作为继续工作的依据。按照软件的生命周期,软件的开发不再只单单强调“编码”,而是概括了软件开发的全过程。因此,每一周期都是按“活动—结果—审核—再活动—直至结果正确”循环往复开展的。
软件生命周期通常包括以下6个阶段。
1)问题定义
问题定义阶段必须回答的关键问题是:“要解决的问题是什么?”如果不知道问题是什么就试图解决这个问题,显然是盲目的,最终得出的结果很可能是毫无意义的。尽管确切地定义问题的必要性是十分明显的,但在实践中它却可能是最容易被忽视的一个步骤。
通过对客户的访问调查,系统分析员扼要地写出关于问题性质、工程目标和工程规模的书面报告,经过讨论和必要的修改后,再得到客户的确认。
2)需求分析
需求分析阶段是一个很重要的阶段,这一阶段做得好,将为整个软件开发的成功打下良好的基础。这个阶段的任务不是具体解决问题,而是确定软件必须具备哪些功能。
用户了解他们所面对的问题,知道必须做什么,但是通常不能完整、准确地表达出他们的要求,更不知道怎样利用计算机解决他们的问题;软件开发人员知道怎样用软件实现要求,但是对特定用户的具体要求并不完全清楚。因此,系统分析员在需求分析阶段必须和用户密切配合,充分交流信息,以得出经过用户确认的系统逻辑模型。通常采用数据流图、数据字典和简要的算法表示系统的逻辑模型。
在需求分析阶段确定的系统逻辑模型是以后设计和实现目标软件的基础,因此必须准确、完整地体现用户的要求。这个阶段的一项重要任务,是用正式文档准确地记录对目标软件的需求,这份文档通常称为软件规范(specification)。
3)软件设计
此阶段主要根据需求分析的结果,对整个软件系统进行设计。软件设计一般分为总体设计和详细设计。良好的软件设计将为软件编程打下良好的基础。
(1)总体设计:又称概要设计。首先,应该设计出实现目标软件的几种可能的方案。软件工程师应该用适当的表达工具描述每种方案,分析每种方案的优缺点,并在充分权衡各种方案的利弊的基础上,推荐一种最佳方案。此外,还应制定出实现最佳方案的详细计划。
上述设计工作确定了解决问题的策略,下面确定怎样设计这个软件。软件设计的一条基本原理是,软件应该模块化,也就是说,一个软件应该由若干规模适中的模块按合理的层次结构组织而成。因此,总体设计的另一项主要任务就是设计软件的体系结构,也就是确定软件由哪些模块组成及模块间的关系。
(2)详细设计:总体设计阶段以比较抽象、概括的方式提出了解决问题的办法,详细设计阶段的任务就是把解决方法具体化。
这个阶段的任务还不是编写代码,而是设计出软件的详细规格说明。这种规格说明的作用类似于其他工程领域中工程师经常使用的工程蓝图,它们应该包含必要的细节,编程人员可以根据它们写出实际代码。
详细设计也称模块设计,在此阶段将详细地设计每个模块,确定实现模块功能所需要的算法和数据结构。
4)软件编码
在此阶段,编程人员应该根据目标软件的性质和实际环境,选取一种适当的高级程序语言,把详细设计的结果翻译成用选定的语言书写的代码,并且仔细测试编写出的每一个模块。在软件编码中必须制定统一的符合标准的编写规范,以保证代码的可读性、易维护性,提高软件的运行效率。
5)软件测试
软件设计完成后要经过严密的测试,以发现软件在整个设计过程中存在的问题并加以纠正。整个测试过程分单元测试、组装测试及系统测试3个阶段进行。测试的方法主要有白盒测试、黑盒测试和灰盒测试等。
在测试过程中需要建立详细的测试计划并严格按照计划进行测试,以降低测试的随意性。应该用正式的文档把测试计划、详细测试方案及实际测试结果保存下来,作为软件配置的组成部分。
6)软件维护
软件维护是软件生命周期中持续时间最长的阶段。在软件开发完成并投入使用后,由于多方面的原因,软件不能继续适应用户的要求。要延续软件的使用寿命,就必须对软件进行维护。
通常有4类维护活动:改正性维护,即诊断和改正在使用过程中发现的软件错误;适应性维护,即修改软件以适应环境的变化;完善性维护,即根据用户的要求改进或扩充软件使其更加完善;预防性维护,即修改软件,为将来的维护活动预先做准备。
每一项维护活动都应该经过提出维护要求、分析维护要求、提出维护方案、审批维护方案、确定维护计划、修改软件设计、修改代码、复查验收等一系列步骤,并且每一项维护活动都应该被准确地记录下来,作为正式文档加以保存。
以上软件生命周期阶段的划分,可能会由于软件规模、种类、开发环境及开发使用的技术方法等因素而有所不同。事实上,承担的软件项目不同,应该完成的任务也会有差异,没有一个适用于所有软件项目的任务集合。
2.软件生命周期模型
软件生命周期模型也称过程模型,它是软件生命周期过程的具体化和实例化。软件生命周期模型定义了软件开发过程中运用的方法及顺序、应该交付的文档资料、为保证软件质量和协调变化所需采取的管理措施,以及标志软件开发各个阶段任务完成的里程碑等。
软件生命周期模型的发展实际上体现了软件工程理论的发展。在最早的时候,软件的生命周期处于无序、混乱的情况。一些人为了能够控制软件的开发过程,就把软件开发严格地区分为多个不同的阶段,并在阶段间加上严格的审查,从而产生了瀑布模型。瀑布模型体现了人们对软件过程的一个希望:严格控制、确保质量。然而,现实往往是残酷的。因为软件的开发过程往往难以预测,瀑布模型根本达不到这个要求,反而导致了其他的负面影响,如产生大量的文档、需要烦琐的审批程序等。因此,人们就开始尝试用其他的方法来改进或替代瀑布模型。
除瀑布模型外,典型的生命周期模型还包括快速原型模型、迭代模型等。迭代模型是统一软件过程(Rational Unified Process,RUP)推荐的周期模型。在RUP中,迭代被定义为包括产品全部开发活动和开发必需的其他外围组件。所以,在某种程度上,开发迭代是一次完整地经过所有工作流程的过程:包括需求工作流程、分析设计工作流程、实施工作流程和测试工作流程。实质上,它类似小型的瀑布式项目。RUP认为,所有的阶段(需求及其他)都可以细分为迭代。每一次的迭代都会产生一个可以发布的产品,这个产品是最终产品的一个子集。在迭代模型中,需要根据主要风险列表选择要在迭代中开发的新的增量内容。每次迭代完成时都会生成一个经过测试的可执行文件,这样就可以核实是否已经降低了目标风险。
快速原型(Rapid Prototype)模型在功能上等价于产品的一个子集。瀑布模型的缺点就在于不够直观,快速原型模型则解决了这个问题。一般来说,应根据客户的需要在很短的时间内解决用户最迫切的问题,完成一个可以演示的产品。这个产品只实现部分的功能(最重要的),它最重要的目的是确定用户的真正需求。在得到用户的需求之后,原型将被抛弃。因为原型开发的速度很快,在安全设计方面是几乎没有考虑的,如果保留原型的话,在随后的开发过程中会为此付出极大的代价。