|
蓝森林 http://www.lslnet.com 2006年6月28日 19:08
cissp-应用和系统开发
在本章中,您将学习到以下知识:
² 不同类型的软件控制和实施
² 数据库概念和安全问题
² 数据仓库和数据挖掘
² 变更控制概念
² 面向对象的编程概念
² 专家系统和人工智能
应用程序和计算机系统开发的首要目的往往是满足功能需求,而很少考虑安全。为了满足两方面的需求,在开发时需要同时考虑安全性和功能性。安全交织在产品核心之中,并在各个层面提供保护。相对于在产品集成到系统中时开发前端或者封装而留下安全漏洞的情况,在设计之初就考虑安全因素的情形要好得多。
11.1 应用程序和系统开发
由于开发目的不同,应用系统控制也形成了很多不同的风格。它们可以控制输入、处理、数字处理方法、进程间通信、与系统和其它程序交互、访问控制和输出等。在开发过程中应该考虑这些功能的潜在风险,在开发的不同阶段,应该进行多种威胁模型和风险的分析。风险分析的目标是防止安全事故,降低数据破坏和受到攻击的可能性。安全控制可能是预防性、探测性或者纠正性的,其表现形式可能是管理方面或者物理方面的控制,更多的情况是技术方面的安全控制(如图11-1)。
图11-1 对应用程序和操作系统有不同类型的安全控制,但是多数是技术方面的控制
特定的应用程序控制依赖于应用程序本身以及它的功能、开发者目标和应用程序所在的环境。如果应用程序纯粹是私有的,并且运行在封闭的可信环境中,那么相对于连接在Internet上提供业务和财务交易的应用而言,就不需要考虑太多的安全控制。安全的诀窍是理解应用程序的安全需求,实施正确的安全控制和安全机制,彻底测试这些安全机制在应用程序中的集成,遵循结构化开发方法,提供安全可靠的发布方法。在安全实践中,情况往往会更复杂。
11.2 设备和软件安全
今天,为了解决安全问题,很多人把目光投向安全设备。这些设备包括防火墙、入侵检测系统(IDS)、探测器和弱点扫描器。造成这种情况的原因是人们普遍认为网络由基本的内外两个部分构成。坏人和潜在的威胁在外部,内部需要保护。从某种程度上讲,这个观点是正确的,因为网络是封闭的环境(通常意义上的可控环境)。然而,我们的环境中通常有电子数据交换(EDI)、远程拨入、Internet站点和虚拟专用网(VPN),今天更是有无线通信、增值网络(VAN)、B2B等新的业务,这些都增加了网络内部和外部概念的复杂性。
软件安全和设备安全的区别在于:软件安全在开发的起始阶段就提供安全概念,而设备安全保护网络边界。周边设备阻止攻击者利用软件存在的安全漏洞。在安全界人们更多地讨论防火墙和IDS,而不是软件设计中的设计缺陷和不良的编程习惯。而实际上,正是软件中的缺陷导致了大多数的脆弱性。图11-2解释了实现安全的两种截然不同的方法。人们倾向于诉诸周边设备解决安全问题,而不是软件开发,原因在于:
过去,在软件开发阶段,安全不是重要的考虑因素。因此,很多程序员不做这方面的考虑。
很多安全专业人员不是软件开发者。
为了进入市场,软件提供商注重的是功能方面,而不是安全。
人们习惯于接受有缺陷的软件,然后应用安全补丁进行修补。
以上种种因素的结合。
图11-2 两种实现安全的途径
在我们这个计算技术不断发展的时代,仅仅靠指手画脚和快速判断是没有任何用处的。二十年前大型主机年代是非常安全的,因为很少一部分人懂得如何操作它们,计算机用户(哑终端)不可能将恶意代码引入主机,计算环境是封闭的。核心协议和框架实在威胁和攻击不盛行的年代开发的,因此,没有安全方面的需求。进而,计算机和软件开始飞速发展,出现了近千个不同的分支。计算机技术和不同类型软件的高度需求增加了对程序员、系统设计员、系统管理员和系统工程师的需求。这种高度需求给计算机界引进了一大批没有经验的人。经验缺乏、技术的快速变化以及市场的发展给安全增加了很多问题,而这些问题很少能得到清晰的理解。尽管很容易凭空说一些大型软件提供商发布存在缺陷或漏洞的软件,然而这是由用户需求驱动的。如果用户理解程序的安全工作原理,理解程序在环境中的集成以及威胁如何发生,那么用户就会需要更加安全的软件,需要更加良好的安全编程和开发实践。
本章解释在软件和开发阶段,如何在源代码级解决安全问题。这需要我们从安全问题的被动响应转换为主动解决,保证不发生安全问题或者将危害降低到最低程度。图11-3展示了现在处理安全问题的方法。
图11-3 软件的市场发布和安全问题处理
11.3 不同的环境需要不同的安全
今天,网络管理员是一个很有竞争性的职位,他们集成不同的计算机系统和应用来满足组织的日益扩大的功能需求,经常购买和快速实施新的功能组件。而组织对这方面的需求增长更快,他们需要在Internet上建立新形象,通过Web站点来实现在线订单、存储信用卡信息、与合作伙伴建立外部网络(Extranet)。对管理员而言,所有这些搀杂在一起将会变得无比混乱:各种协议、设备、界面、兼容性问题、路由和交换技术、远程通信和管理程序,以至于管理员无法忍受而宁愿去Montana放牧。
在这种情形下,人们期望、需要并且依赖软件的安全性。当安全危害在网络中蔓延时,各种指责开始了,可靠性问题像烫山芋一样被人们推来推去,管理员也无可奈何,只好摇头叹息了。这些需要对环境的理解,理解环境现状和工作原理,这样新技术才可能以更加一种可控的方式实施,更容易得到理解。
11.3.1 电子商务
开发一个简单的页面,在Internet上出卖简单商品的时代已经过去了。今天,需要开发顾客前端、复杂的中间件和三层数据仓库,并且它们必须无缝集成在一起配合工作。当这种类型的环境复杂性日益增长时,跟踪错误和安全危害的任务将变得及其困难。(本章将贯穿始终地描述这种环境。)
11.3.2 客户/服务器(Client/Server)模型
客户/服务器体系使得应用系统可以和跨越不同操作系统和硬件的多种平台分开。客户端请求服务,服务器端响应这些请求。服务器执行数据处理服务并向客户端返回处理结果。客户端执行应用程序的前端部分,服务器执行后台部分,而通常后台程序的工作量更大。
前端通常包括用户界面和本地数据操作,并提供可以从应用程序的服务器端请求服务的数据通信机制。
11.4 环境和应用程序控制
软件控制可以通过操作系统、应用程序或者数据库管理控制来实现,实际中则通常是综合三种控制方式。每一种控制方式都有自己的长处和弱点,但是如果能够充分理解这些特点,并且在编程时给予足够的注意,那么许多不同类型的危害就可以避免。主要以来操作系统控制的一个弱点是:操作系统可以控制主体对不同客体的访问,限制主体在系统内的行为,但是对一个应用程序而言则没必要这样要求。如果应用程序存在一个由恶意程序代码造成的安全威胁,而操作系统很难发现或者预测这种威胁,并在危害发生时立即进行审计记录。文件系统是很多应用程序工作的自由环境。我们很难要求操作系统可以理解不同程序之间的细微差别和它们的内部机制。
另一方面,应用控制和数据库管理控制则针对特定的需求和安全威胁。尽管应用程序可以通过限制输入数据类型或者不允许特定用户查看保存在敏感数据库中的数据来保护数据安全,但是它不能阻止用户删除msdos.sys或在ARP表中插入欺骗数据。操作系统和应用控制有它们的用途和限制。一个窍门是找出一个控制在何处停止作用,而实施的下一类型的控制可以继续完成这项安全功能。
需要理解不同类型的控制,并且应用它们实现安全平衡
实际中主要由环境设备提供安全,而不是嵌入到应用程序中的控制。环境设备可以建立在很多应用之上,它们可以被集中管理平台控制,或者进一步由应用程序控制。然而,这种方法往往不能够提供必要的安全粒度水平,不能处理由于代码和设计程序问题造成的威胁。防火墙和访问控制机制可以通过阻止攻击者利用缓冲区溢出而提供一定级别的保护,但是正确的软件开发和编码实践必须得到实施——而这是真正保护问题的核心。
11.5 功能复杂性
编程是一个复杂的过程——不仅代码本身复杂,而且子程序交互、全局和局部变量、由其它程序的输入、输出到其它应用程序、预测用户输入、计算方法、对可能结果处理的限制,所有这一切都充满了复杂性。很多情况下,试图说明所有的what-if语句或者追求编程的谨慎都可能减少应用程序的整体功能性。
当出现应用程序功能性和范围限制时,程序的市场份额和潜在利润都将可能减少。通常,在安全性和功能性之间会存在一个平衡,而在开发过程中,功能性往往被认为是最重要的。
这就意味着程序员和应用程序设计师需要寻找一个功能需求、安全需求以及安全机制三者之间的平衡点。这将会给本已十分复杂的应用开发任务增加更多的复杂性。
可能存在不止一种方法来解决问题,但是随着方法数量的增加,也就很难最终判断哪种方法能够产生的效果是好是坏。很多程序从自身的不同模块、其它程序、系统或者用户输入接受数据。每一种方法都需要遵循系统的方法,充分考虑到每一种可能的情形,并且进行测试以提供更深的保证度。重要的是,每一个模块都能够被独立测试,并且和其它模块一致。这种水平的理解和测试将通过捕捉可能被利用的弱点而使产品更加安全。
11.6 数据类型、格式和长度
我们都听说近来流行的各种缓冲区溢出弱点,似乎这是编程世界的一个新事物。然而,它不是一个新事物,并且一直被不断地利用。
在第五章中我们已经讨论过缓冲区溢出,并且解释了当应用程序不进行实际输入数据长度检查时攻击的执行过程。溢出的代码数据将在特权模式下被执行,使得攻击者获得系统的控制权。如果程序员编写的程序期望输入数据长度为5KB,那么就需要在代码中处理,当数据输入时分配适当的空间。然而,如果程序不确定可以接受5KB数据并且最多只能接受5KB输入数据,那么攻击者就可能输入5KB供程序正常处理,而额外输入的50KB数据中包含的恶意指令代码同样被系统执行。
处理数据输入时,长度并不是唯一需要考虑的对象,输入数据同样需要正确的类型和长度。如果程序期望输入ACSII码,那么它就不能接受十六进制数或者二进制数的输入。
接受的输入数据的值应该有一个合理的范围。如果程序期望Stacy输入她从支票帐户转存到储蓄帐户的金额,那么她不能输入“Bob”。这就是输入数据的格式和类型的问题(数字还是字母),但是参数本身同样需要进行检查以防止入口欺骗,保证程序可以在错误发生的最初位置停止,而不是等错误参数传递到计算程序或者逻辑处理之后停止。
这些例子同程序员面对的真实世界相比时分简单。然而,为了安全和功能性的目的,开发安全需求时需要保证接受正确的数据类型、格式和长度的输入参数。
11.7 实施和缺省配置问题
计算机技术领域中很多人都已经认识到,初始的工程实施还远远谈不上安全。多数的安全功能需要在安装之后进行配置或者打开,对没有IT经验的人来说,认识不到这一点是非常危险的。由于各方面的原因,Windows NT的不安全性受到了各方的批评,但是系统可以通过多种途径加强安全,只是其初始安装处于不安全的状态。造成这种情况的原因是系统为了集成到不同的环境中不得不进行宽松配置,同时也为用户提供一个比较友好的安装方式。如果一个用户安装新的软件包时经常弹出“拒绝访问”的消息,那么他就可能失去耐心,进而归咎于软件提供商。
这同样将开发者和设计师置于艰难的境地。当安全软件或者安全设备初始安装时,应该默认设置为“拒绝一切访问”。如果用户安装一个包过滤防火墙,这就意味着防火墙默认拒绝一切进入网络的流量。然而,这需要用户知道如何进一步配置防火墙并使它正常工作。在安全、功能性和友好性之间存在着这样一条界线:如果应用程序设计得对用户十分友好,它可能在安全性方面有所缺失;需要在容错、对话框、用户向导和操作步骤指令方面进行大量的设计工作。可悲的是,这些额外的代码使得源程序庞大臃肿,可能存在着许多不可预见的危险。因此这使得软件提供商很难抉择,但通常他们会将牟取利益放在首位。
11.7.1 实施
在网络环境中,实施错误和错误配置是造成大量安全问题的重要原因。很多人没有认识到系统安装之后会运行着大量的服务。这些服务为攻击者提供了攻击过程中需要的信息,甚至很多服务本身就是进入网络的一条路径。NetBIOS可以在Windows环境中提供资源共享,远程调用服务(RPC)使得用户可以无限制地使用命令行界面或者执行其它程序。下面是不必要的服务提供非法系统入口的两个例子。
很多系统运行着这样一些实际没有用途的服务,像FTP、Telnet、IRC等,这些服务往往又没有实施任何安全措施。在系统安装时这样一些服务会被缺省安装并打开,从而为攻击者提供了方便之门。
由于软件提供商始终将友好性和功能性放在首位,他们的产品的缺省安装往往只提供很低水平的安全保护,甚至没有。对提供商而言,他们很难清晰地了解软件安装的不同环境的安全需求水平,因此他们通常置之不理。学习正确配置并使系统达到所需的安全防护水平就成为了进行系统安装的人的责任。
实施和安全中的另一个问题是存在大量未进行修补的系统。一旦发现安全问题,软件提供商会开发安全补丁来解决和修补这些安全漏洞。然而,这些补丁大部分不能安装到用户存在漏洞的系统上。其原因多种多样:有的管理员不能及时关注安全信息,有的没有认识到安全补丁的重要性,有的害怕补丁会导致其它事故。这些情况都普遍存在,但是都导致同样的后果——不安全的系统。在补丁发布几个月甚至几年后,有的漏洞仍然被人利用。
不幸的是,安全补丁(或者服务补丁)可能会影响到系统其它运行机制。在补丁正式应用到系统之前,需要在相同环境内进行测试,以防止服务瘫痪或影响到网络运行和业务生产。
11.8 故障状态
很多情况都是不可预测的,因此很难为各种意外做出计划。然而,我们可以从整体意义上对不可预测的情况进行计划,而不是考虑每一种可能的情况。如果应用程序由于某种原因失败,我们应当将其恢复到一个安全状态。这可能需要应用程序关闭或者提供给用户一个登陆界面从应用程序的初始状态开始运行。这就是系统“蓝屏”并重新启动的原因。当发生这种情况时,系统处于不可识别的状态或者不安全状态,系统会转储内存数据并重新启动。
在第五章中讨论了不同的系统状态,进程可以在“特权态”或者“用户态”运行。如果在“特权态”执行的程序失败,这些进程会正确关闭并释放资源以保证中断的系统不会提供可被利用的危险。如果一个特权进程没有被正确关闭而仍处于活动状态,攻击者可以利用这个处于“特权态”的进程进入系统。这也意味着攻击者可以获得管理员或者root权限,系统可能遭到更严重的破坏。
11.9 数据库管理
数据库用于保存组织中重要的数据已经有很长的历史,一直被认为时组织最有价值的资产。正因为此,数据库一直只处于数据库管理员或网络管理员管理的监管之下,很少为人所知。事实上,外界对数据库了解的越少,对安全越有利。用户通常通过一个间接的客户端界面访问数据库,访问行为也被严格控制以保证数据库和数据库自身结构数据的机密性和完整性。
注意:数据库管理系统(Database Management System, DBMS):数据库管理系统通常指一组管理结构化数据的程序,可以为不同类型的用户提供数据查询能力。
由于组织将内部网络连接到Internet上,而通常包含一个间接可以访问的后台数据库,原来的规范就已被打破。过去,公司的员工访问数据库中的客户信息,而不是由客户自己去访问。今天,很多公司允许客户通过浏览器访问数据库中的信息,浏览器通过中间件连接后台数据库。这增加了应用的复杂程度,数据库可以被以前所未有的方式访问。
例如在银行界,网上银行十分盛行。很多金融机构为了保持竞争优势,将很多客户可能需要的服务累加到网上银行中。但是网上银行不仅仅是和其它柜台服务一类的服务。多数银行工作在封闭(或者半封闭)的环境中,将其连接到Internet上是一项艰巨的任务。网络边界需要保护;中间件需要开发或者购买;数据库前面需要部署一个防火墙,最好是两个。多数情况下,业务应用层的组件需要从数据库中提取数据来处理客户请求。
可以只限制允许的角色(role)访问数据库。数据库管理员可以指定特定的角色,只允许他们访问数据库。每一个角色将被分配一定的权力和权限,客户和公司的员工将被赋予不同的角色。任何不属于这些角色的用户将被拒绝访问数据库。如果攻击者攻破了防火墙和其它网络保护机制,可以向数据库提交访问请求,但是由于他不属于某一既定角色,数据库此刻同样是安全的。这个过程简化了访问控制,保证了用户或者恶意攻击者不能直接访问数据库,而只能通过特定角色帐户间接访问数据库。
图11-4 基于角色(Role)实现数据库安全
11.9.1 数据库管理软件
数据库是以某种有意义的方式存储的一组数据,它允许多个用户和应用程序在需要时访问、查看和修改数据。数据库由能够提供这些功能的软件管理,同时提供访问控制、数据完整性和数据冗余,并建立不同的数据操作过程。这种软件就是数据库管理系统(Database Management System, DBMS),通常由数据库管理员(Database Administrator)控制。数据库不仅存储数据,同时对数据进行处理,或者以某种有意义的逻辑形式重现数据。数据库管理系统与程序、用户和数据库中的数据进行交互,帮助我们更加有效地存储、组织和获得信息。
数据库为收集到的数据提供结构化机制。由于不同的组织或部门处理不同类型的数据,需要对信息执行的功能操作不同,因此数据库实现中的结构化规范也不尽相同。它们的工作负载,数据之间的关系、性能需求和安全目标都会有所差别。
由于对数据库的需求存在差异,为了满足业务和组织需求,也存在这实现数据库的不同数据模型。
数据库相关术语
记录(Record):关系数据的集合
文件(File):相同类型数据的集合
数据库(Database):文件的交叉集合
数据库管理系统(DBMS):管理和控制数据库
基础关系(Base relation):存储在数据库中的一张表
元组(Tuple):数据库中的行
属性(Attribute):数据库中的列
主键(Primary Key):使得行具有唯一性的列(一个表必须拥有一个主键)
视图(View): 控制主体访问特定数据而定义的虚拟关系
外键(Foreign Key):表中的列是其它表的主键
存储单元(Cell):行和列的交汇
架构(Schema):容纳描述数据库的数据
数据字典(Data dictionary):描述数据元素和相互关系的中心库
11.9.2 数据库模型
数据库模型定义了不同数据元素之间的关系,规定了如何访问数据,定义可可接受的数据操作和提供的数据完整性类型,以及如何组织这些数据。数据库模型提供了一个用概念化形式表示数据的正式方法,提供了数据库中存储的数据的必要的操作方式的描述。这里我们介绍三种数据库模型。
关系数据库模型使用行和列包含和组织信息。如图11-5。关系数据库模型是今天应用最广泛的数据库组织形式。它以表(table)的形式表示信息。一个关系数据库由一些二维表构成,每个表包含行、列和存储单元。主键(Primary Key)是连接一条记录其它相应值的字段。例如在下面的表中,主键是字段Product,G345和G978。当一个应用程序或者其它记录引用这个外键时,实际上引用的是这一行的所有数据。
图11-5 关系数据库(Relational Database)以表结构存储数据
层次数据库模型是另一种通用的数据库模型(如图11-6)。数据元素之间的结构和关系与关系数据库中不同。层次数据库模型由记录(Record)和字段(Field)构成,它们之间是逻辑的树形关系。
父节点可以有一个子节点或者多个子节点,也可以没有子节点。树形结构包含许多分支(Branch),分支又会有一定数量的叶子(Leaf)节点,或者数据字段。这些数据被良好定义,有预先定义的访问路径,但是不如关系数据库灵活。层次数据库通常用于映射一对多的数据关系。
图11-6 层次数据库(Hierarchical Database)使用树形结构和父/子(Parent/Child)关系
分布数据库模型中,数据存储在多个分布的数据库中,它们逻辑上相互连接(如图11-7)。分布数据库模型使用层次结构,但是低级数据元素可能拥有多于一个的父节点。这种模型用来表示多对多的数据关系。
不同的数据库可能位于网络上的不同位置,或者位于不同的网络之中。由于它们逻辑上是相互连接的,用户可以将其看作一个整体数据库。当用户访问数据时,不需要知道所访问的哪一个数据库,一个数据库可能将用户转移到另一个数据库,这对用户而言时透明的。
这个模型使得不同的管理员可以管理不同的数据库,然而整体逻辑数据库必须由一个人或者组进行管理。在每个数据库包含特定信息,但是存在负载均衡、容错和用户切换频繁的情况下,适用分布数据库。
图11-7 分布数据库可能包含多个不同物理区域的数据库,它们逻辑上相互连接,被当作一个整体数据库看待。
11.9.3 关系数据库组件
像其它软件一样,数据库内嵌编程语言。例如数据描述语言(Data Definition Language,DDL)用来描述数据架构,数据库操作语言(Data Manipulation Language,DML)用来检查和操作数据库中的数据,数据控制语言(Data Control Language,DCL)用来定义数据库的内部组织,用户可以使用查询语言(Query Language,QL)对数据库进行查询和访问。
不同的厂商应用数据库模型存在差异,每种数据库的类型也不相同。然而,在多数情况下,数据库都包含一些核心基本功能:
数据描述语言(Data Definition Language,DDL)
数据库操作语言(Data Manipulation Language,DML)
查询语言(Query Language,QL)
报表生成器(Report generator)
DDL定义了数据库的结构(Structure)和数据架构(Schema)。结构说明表的大小、布置、视图和数据元素关系。数据架构描述数据库存储和操作的数据类型以及它们的属性。DDL定义了数据库的结构、访问操作和完整性过程。
DML包含用户视图、操作和应用(检索、增加、编辑、排序、删除命令)数据库的所有命令。QL使用户可以对数据库提出查询请求,报表生成器提供用户定义方式的数据过程输出。
11.9.4 数据字典(Data Dictionary)
数据字典是一个描述数元素和数据关系的中心库,存储数据用法、数据关系、数据来源和数据格式等关键信息。数据字典是一个控制数据库数据的集中管理部分,描述成组数据元素和数据库之间的交叉引用关系。
数据字典是数据元素定义、架构对象(schema object)和引用键(reference key)的集合。架构对象可以包含表、视图、索引、过程、函数和触发器。数据字典可以包含列的缺省值、数据完整性信息、用户名、用户的权限和角色以及审核信息。
数据库管理软件读取数据字典,确认架构对象存在,并检查特定用户的进程访问权限(如图11-8)。当检索数据库时,用户对数据的访问被特定的视图所限制。在数据字典中定义了对每个用户的视图权限设置。用户可以从数据字典中发现关于数据库本身的信息。当需要增加新的记录、表、视图或者架构时,应该更新数据字典反映这些变化。
图11-8 数据字典是包含数据库信息的集中程序
11.9.5 主键(Primary Key)和外键(Foreign Key)
主键是表的唯一性标识,主键的值必须是唯一的。每个表必须拥有一个主键。当用户请求查询一条数据记录时,数据库通过这个唯一的主键跟踪这条记录。如果主键不唯一,那么数据库就确定一条数据记录。在下面的图示中,狗的名字——Dog作为Table A的主键。
外键不同于主键,但是它们关系密切。如果一个表中的属性是另一个表的主键,那么这个属性就称作“外键”。一个表的外键不一定是这个表的主键,只是包含同另一个表的主键相同的信息。在下面的图示中,Table A的主键是 Dallas,由于Table B的一个属性引用的这个主键,因此它是Table的外键。这是跟踪数据库数据关系的另一种方式。
11.9.6 完整性
像网络上其它资源一样,数据库也会遇到并发(Concurrency)问题。为了保证不同访问主体都可以访问最近的更新数据,必须处理并发问题。如果一个工作组使用一份价格表,包括下周供应商计划并预算利润,那么这份报价就是一个很重要的文件。如果Dan和Elizabeth从文件服务器上复制到本机工作站,那么他们都得到一份原始数据拷贝。如果因为Dan在前三天的销售状况很好,他计算机图书数量从120改为5。他同样使用报价表中的价格估计下周的利润。Elizabeth降低了几个软件包的价格,由于看到计算机图书的数量仍然超过100本,她决定暂时不为下周订货。Dan和Elizabeth没有彼此交流关于此事的信息,但是都在价格表上进行了修改。
Dan将自己修改的版本复制到服务器上,而Elizabeth在30秒钟后也将自己的复制到服务器上。于是服务器上的价格表版本只有Elizabeth做的修改。由于他们的修改没有进行同步,因此他们都在使用不正确的版本。Dan不知道Elizabeth降低了售价,同时没有为下周订货,而Elizabeth不知道库存已经减少到5本,下周这种图书将缺货。
在数据库中会发生同样的情形。如果没有实施控制,两个用户可能同时访问和修改同一数据,在动态环境中,这可能造成危险。为了解决并发问题,进程可以锁定数据库中的表,进行更新,然后释放锁定。然后下一个进程访问锁定数据表数据表,进行更新。这样就可以保证两个进程不在同一时间访问同一个数据表。页、表、行、列都可以被锁定以保证在同一时刻不会有两个数据更新进程,这样每一个进程都可以访问到正确的信息。
数据库软件执行两种类型的完整性服务:语义完整性(Semantic Integrity)和参考完整性(Referential Integrity)。语义完整性机制保证执行结构化规则和语义规则。这些规则与一下因素有关:数据类型、逻辑值、唯一性约束以及可能影响到数据库结构的操作。参考完整性机制保证记录不会引用不存在的记录的主键,或者空值的主键。这保证了元组由主键唯一确定。在前面的图例中,主键名是dog。为了保持表的完整性,每一个元组必须包含一个主键。如果表不包含主键,数据库就不能引用此表。
同样,数据库必须不能约束不匹配的外键值。每个外键指向一个存在的主键,在前面的图例中,如果Table B的主键值是Dallas,那么相关联的Table A的主键必须存在相同的值,即Dallas。如果外键值不能匹配,那么它们之间的关系将被打破,数据库也就无法正确引用信息。
其它一些配置性操作帮助保护数据库中数据的完整性。这些操作包括回滚(Rollback)、提交(Commit)和检查点(Checkpoint)。
回滚(Rollback)指的是结束当前事务并取消对数据库做的更改。这些更改可能是数据本身发生的更改或者是架构(Schema)修改。执行回滚后,所作的变更被取消,数据库恢复到先前的状态。回滚发生在数据库出现意想不到的故障或者外部接口处理程序错误时。数据库恢复到原始状态,而不是仅仅重传或者更正部分数据。同时,数据库记录错误和操作日志,以便日后审查。
提交(Commit)是指中断事务操作,执行用户做出的数据变更。顾名思义,一旦提交命令执行,用户变更就得到确认,并反映到数据库中。这些变更可以是数据或者数据架构,通过提交操作,其它用户或者应用程序访问到更新的数据。如果用户数据变更的提交命令没有正确执行,那么数据库会执行回滚命令。这保证了不会由于发生部分变更而引起的数据混乱。
检查点(Checkpoint)用来保证系统发生故障或者探测到错误时,用户可以会到系统故障之前的状态。举一个概念化的例子,Dave在键入 ”Jeremiah was a bullfrog. He was <检查点>; a good friend of mine” (系统插入一个<检查点>;)。系统由于故障而重新启动。当Dave回到数据库应用程序,他看到数据库中的记录内容是 ”Jeremiah was a bullfrog. He was”,但其它键入的内容丢失了。因此,检查点保存了他的部分工作。
在数据库中,检查点很容易实现,但是需要权衡检查点的数量。检查点太多会降低数据库系统的性能;检查点太少,故障后需要重新输入的内容增多,则可能导致数据丢失的风险或者降低生产效率。检查点可以依照时间间隔产生,或者是用户的特定行为,或者是数据库处理事务或变更的数量。数据库可以每15分钟产生一个检查点,或者每完成20个事务处理产生一个检查点,或者在用户每结束一个记录输入时产生一个检查点,也可以在每完成12次变更时产生一个检查点。
因此,检查点可以为用户在系统故障时提供数据恢复的功能。检查点可以降低故障损失,使数据库工作更为协调。
11.9.7 数据库安全问题
关于数据库安全,我们主要讨论两个问题:聚合(aggregation)和推理(inference)。聚合是指这种情形:如果用户没有访问特定信息的权限,但是他有访问这些信息的组成部分的权限。这样,她就可以将每个组成部分组合起来,得到受限访问的信息。用户可以通过不同的途径得到信息,通过综合就可以得到本没有明确访问权限的信息。
注意:聚合(Aggregation)指的是组合不同来源的信息的行为。用户没有明确的权限可以访问组合起来得到的信息,而组合得到的信息比信息的各个组成部分拥有更高的机密性。
下面是一个简单的概念化例子。假设数据库管理员不想让Users组的用户访问一个特定的句子“The chicken wore funny red culottes.”,如图11-9,他将这个句子分成六个部分,限制用户访问。Emily可以访问A、C、F三个部分,由于她是个特别聪明的人,她可以根据这三个部分结合起来得出这个句子的部分。
为了防止聚合,需要防止主体和任何主体的应用程序和进程获得整个数据集合的权限,包括数据集合的各个独立组成部分。客体可以进行分类并赋予较高的级别,存储在容器中,防止低级别权限的主体访问。对主体的查询,可以进行跟踪,并实施基于上下文的分类。这将记录主体对客体的访问历史,并在聚合攻击发生时限制访问企图。
图11-9因为Emily有访问A、C、F三部分的权限,她可以通过聚合得到秘密信息
另一个安全问题是推理(Inference)和聚合很相似。推理指的是主体通过他可以访问的信息推理出受限访问的信息。当可以由安全级别较低的数据描述出较高级别的数据时,就会发生推理攻击。
注意:推理是得到不是显性可用的信息的能力。
例如,如果一个职员不应该知道军队在沙特阿拉伯的行动计划,但是他可以访问到食品需求表格和帐篷位置的文档,那么他就可以根据食品和帐篷运送的目的地推算出军队正在向Dubia地区移动。在文档安全性分类中,食品需求和帐篷位置文档是机密文档(Confidential),而军队行动计划是绝密文档(Top of Secret)。由于不同的分类,这个职员可以根据他知道的信息推理出他不应该知道的秘密。
一个办法是防止主体或者与主体有关的应用程序和进程间接得到能推论的信息。在数据库开发过程中,可以实施基于内容或者基于上下文的分类规则来解决这个问题,对主体的查询请求进行跟踪,限制可以进行推理的查询模式。
数据库安全与操作系统安全的实现方法有所不同。在操作系统中,对主体的鉴别和认证可以控制访问权限。鉴别和认证可以通过访问控制表(Access Control List)、权限表(Capability table)、角色或者安全标识(security label)来实现。操作系统只需要决定主体是否有文件访问权限,而不需考虑文件的具体内容。如果Mitch可以访问文件A,即使文件中包含有关于冷战策略的机密信息也没有关系。而另一方面,为数据库安全制定访问控制策略时,需要考虑文件的内容,即所谓的基于内容的访问控制(Content-dependent Access Control)。这种类型的增加了处理的工作量,但是却提高了控制粒度。
防止推理攻击的一种措施叫做单元抑制(Cell Suppression),采用数据库分隔,或者噪声和扰动。单元抑制时一种用来隐藏或者不显示特定存储单元的内容,防止这些信息被用来进行推理攻击。分隔数据库(Partitioning a database)包括将数据库分成不同的部分,使未授权用户很难访问到可以用于推理攻击的相关的数据。噪声和扰动是一种在数据库中插入伪造信息的技术,目的是为了误导和迷惑攻击者,使得真实的推理攻击不能成功。
多数情况下,数据库在规划和开发过程中并没有将安全集成进来。安全需要事后考虑,作为替代,往往需要开发一个数据库可信前端(front end)。这种方法限制了安全粒度,安全功能可以发挥作用。
关于安全的一个永恒的主题就是有效安全和功能之间的平衡。多数情况下,在安全方面做的越多,在功能方面的的损失越大。虽然安全状态是我们的期望结果,但在实际中引入安全而不影响生产效率也是很重要的。
11.9.7.1 数据库视图(View)
不要每个人都可以访问所有的信息,只能有选择地赋予信息访问权限。
数据库可以运行一个组或者一个特定用户访问特定信息,而限制另一个组访问。这种功能通过数据库视图(Database View)实现。如果数据库管理员只允许中层管理者看到部门收支情况,但不允许他们看到整个公司的财务状况,就可以利用数据库视图。高层管理者可以看到所有的视图,包括部门和整个公司的财务数据,而每个经理只能查看本部门的数据。
像操作系统一样,数据库可以实施任意访问控制(Discretion Access Control, DAC)和强制访问控制(Mandatory Access Control, MAC)(参见第4章)。因此,可以根据组成员、用户权限或者安全标识控制视图访问。如果实施任意访问控制(DAC),可以通过基于身份标识、鉴别和认证授予用户或组以视图的访问权限。如果实施强制访问控制(MAC),可以采用基于安全标识和数据机密性分级对组和用户进行访问权限的授予。
11.9.7.2 多实例(Polyinstantiation)
有的时候,不希望低安全级别的用户访问和修改高安全级别的数据。有不同的方法处理这种情况。一种方法是当低级别用户访问高级别数据时,拒绝访问。然而,这就相对于间接告诉访问者他要访问的对象中包含敏感信息。
另一种处理方法是多实例(Polyinstantiation)。多实例建立了相同主键的多元组和由安全级别定义的实例之间的关系。当一条信息插入到数据库中时,需要限制低级别用户访问这条信息。通过建立另一组数据迷惑低级别用户,使用户认为他得到的信息是真实的,而不是仅仅限制信息的访问。例如,海军基地有一艘租用Oklahoma船舶公司从Delaware到Ukraine的运载武器的货船,这种类型的信息应该划为绝密信息(Top of Secret)。只有声明拥有绝密信息权限的人才可以访问。可以创建一个虚假信息文件,内容是Oklahoma船舶公司有一艘从Delaware到非洲的食品货运船,如表11-1。很明显,Oklahoma的船只已经离开,但是低安全级别的用户以为船去了非洲,而不是到Ukraine。这就保证低安全级别的用户不去试图过问这艘船的真正使命,他们已经知道这艘船已经没有意义了,而去寻找其它运输武器的船只了。
注意:多实例是通过变化值或者其它属性来交互生成客体详细信息的过程。
表11-1 一个为低安全级别用户提供替代信息的多实例(Polyinstantiation)例子
Level Ship Cargo Orign Destionation
Top Secret Oklahoma Weapons Delaware Ukraine
Unclassified Oklahoma Food Delaware Africa
多实例为同一客体创建了两种不同的视图,因此低级别的用户无从知道真正的信息,同时也阻止了他试图进一步以其它途径获得真正的信息。多实例是一种为没有相应安全级别的用户提供替代信息的方法。
11.9.7.3 联机事务处理(Online Transaction Processing, OLTP)
联机事务处理(Online Transaction Processing, OLTP)用于多数据库集群用来提供容错和高性能的情况。OLTP提供一种监测问题的机制,并在问题发生时立即进行适当处理。例如,如果一个进程由于某种原因停止处理,OLTP中的监视机制探测到这个问题并试图重新启动进程。如果进程不能被重启,正在进行的事务处理将会执行回滚(Rollback)操作,保证数据不会被破坏和事务处理的完整。任何被删除的错误或者非法事务处理将会被记录到事务日志中,以便日后审查。
如果必要,OLTP可以对入站请求做负载均衡。如果数据库更新请求增多,一个系统由于负载增大而性能下降,OLTP将将其中的一部分请求转移到另一系统上。这将保证用户或者任何发出请求的进程能够及时处理,而不必长时间地等待一个事务处理完成。
如果一个以上的数据库系统,数据库同步就变得很重要。如果数据库A中Katie的帐户余额是$3,500而数据库B中的数字是$10,000,这将导致一些问题,如图11-10。造成数据不符的原因是Katie提款几千美元,而只有一个数据库处理了这个请求。如果实际余款额是$3,500,Katie提请一个查询余额的请求,这个请求有可能会被提交到另一个数据库。她看到的余额有可能仍是$10,000。尽管这可能使Katie感到高兴,但是这是个错误的数据。OLTP将保证所有的数据库同步完成后才结束事务处理。这是一个两段提交服务(two-phase commit service)。
图11-10如果每个数据库没有及时更新最新的数据,那么将会发生各种问题
11.9.8 数据仓库(Data Warehousing)和数据挖掘(Data Mining)
数据仓库指的是为了信息检索和数据分析,将多个数据库联合成一个大的数据库。从各个不同的数据库中提取数据传输到一个中央数据存储区,这个存储区就叫做数据仓库(Data warehousing)。数据仓库使用户可以不用查询多个数据库,而只查询一个实体。
这并不只是一个将各个数据库数据镜像到某个存储区的过程。实质上,它是一种选择有用信息,然后通过处理将数据以一种更易接受的方式表达出来的方法。展示给用户之前,相关数据被总结和关联,用户得到的是经过精简的、更适合用户需求的数据。
尽管数据仓库提供更方便的访问控制,但是由于它的集中性,数据仓库需要更严格的安全。如果入侵者进入数据仓库,那么他就可以立即访问整个组织的数据信息了。
数据挖掘(Data Mining)是对数据仓库中的数据进行进一步处理以得到更有用信息的过程。数据挖掘工具被用来发现数据的联合和相关性来生成元数据(Metadata)。元数据可以单个信息子集中隐含的相关性。它可以用来发现不明显的异常模式。下面举一个使用元数据发现保险欺骗的简单例子。如果一个数据库中存储了几百万用户的信息、需求、特定爱好等数据,数据挖掘工具发现需求中的某种模式,每次John Smith搬迁二到三个月后他就会有购买保险需求。例如在1967年搬家后两个月发生了一次火灾,1973年搬家后三个月他丢失了一辆摩托车,而在1984年搬家后三个月他家被强盗洗劫。这样就形成了一个模式。由于他多年来是几家不同的保险公司的客户,文件被更新而没有检查,或者文件存放在一个供客户查询的集中的地点,因此,人工很难发现这样的模式。
数据挖掘可以检查复杂的数据,通过模糊逻辑(Fuzzy logic)、集合理论(set theory)、神经网络(neural network)技术来简化查询,执行数学函数,查找到数据中的隐含模式。从某种意义上说,元数据比它的原始数据来源更有价值,应当收到高度保护。(模糊逻辑和神经网络将在后面的“人工智能”一节中介绍)。
图11-11数据挖掘工具用来从数据仓库中提取数据,鉴别模式、以有用的方式提交给用户。
11.10 系统开发
如果不是通过在开发后期应用第三方软件作为前端,而是贯穿整个系统和应用程序开发生命周期进行安全的规划和管理,还是能够取得很好的安全的。从项目启动阶段到设计阶段、编码阶段、实施阶段和运行阶段,在这个生命周期中有安全风险、安全分析和安全事件会发生,这些问题应该在各个阶段得到处理。如果在项目开发后期加入安全的考虑,而不是在各个生命周期的阶段都考虑,那么安全的成本和时间都将会增长很多。安全不是短跑项目,而是充满险阻和困难的长征。
图
很多开发者、程序员和系统设计员都很清楚这一点:如果不将安全集成在规划和设计阶段考虑,而是将安全作为系统开发的最后一个阶段,那么开发成本将会变得十分昂贵。不同的安全组件可以影响到系统的很多方面,如果在最后阶段设计安全,那么毫无疑问它将会给系统带来副面作用,影响已经开发的功能,甚至导致系统运行异常。开发者将花费大量的时间重新检查代码、重新编写功能模块甚至需要重新考虑系统体系架构。
11.10.1 开发管理
很多开发者明白良好的项目管理将会使项目顺利案计划进展,合理分配必需的资源,提供必需的信息,充分考虑可能遇到的各种情况。项目管理使产品开发的重要部分,同样,安全管理是项目管理的重要部分。
安全计划(Security plan)应该在项目开发开始就制定,并且集成到功能计划中,以保证安全不被忽视。第一个安全计划应该是广泛的,涉及到各个方面,并且引用其它参考文档以得到更详细的信息。这些参考文档包括计算机标准(如RFC文档,IEEE标准和一些最佳实施)、先前项目文档、安全策略、认证声明、事件处理计划以及国家或国际安全指南(如橙皮书、红皮书、通用准则(Common Criteria, CC)等)。这些文档将使安全计划更易读易用。
安全计划应该有自己的生命周期。有时安全计划需要进行增加或者删减,并在以后的项目过程中进行详细解释。保持安全计划的更新对以后的引用是很重要的,因为一旦大型复杂项目开始,经常会出现对项目跟踪的失控。
安全计划和项目管理活动需要进行审核以保证安全相关的决定可被理解。当系统需求保证被确认时,就表明在生命周期的各个阶段和所有的过程、开发、决策中已经考虑安全因素,并且项目中发生的一切活动都将被审查。因此重要的一点是,反映系统或者产品如何建立和在环境中实施后如何运作的文档应当尽量准确。
11.10.2 生命周期
关于系统和应用开发有几种模型,其中都包含了生命周期的变化。本节只描述其中一种模型。每个模型都基本表达同一种过程;他们主要的区别是如何开发以及生命周期被划分的不同阶段。
一个项目可能从一个好的想法开始,然后由程序员和工程师实现它,或者是遵循生命周期进行精心设计和构造。第一种方法看上去有些可笑,因为用户需求和一些步骤被跳过,缺少文档,产品可能在较短的时间内按照预算开发完成。然而,真正有乐趣的是由一个项目小组完全按照生命周期的各个阶段进行开发,他们的产品更可靠,更加容易被市场接受,项目小组也将会得到长期的回报,也很少有必要去开发一些服务和安全补丁包来修补第一个版本出现的问题。
系统或者产品通常会遵循如下生命周期阶段:
项目启动(Project initiation)
功能设计分析和规划(Functional design and planning)
系统详细设计(System design specifications)
软件开发(Software development)
安装和实施(Installation/implementation)
运行和维护(Operational/maintainance)
处理(Disposal)
你可能注意到安全并不是某一个阶段的核心,因为安全应当贯穿整个生命周期的所有阶段。在产品发布后解决安全问题将会比在产品开发过程中解决增加很大的成本。功能性是产品开发的驱动力,在这个范畴中需要考虑有关的一些事项;但是同样需要在产品生命周期的各个阶段考虑安全问题。
11.10.2.1 项目启动
图
在这个阶段中,项目组的每一个人都应当充分理解项目需求和项目要求的范围。在市场上,特殊的用户会有新的系统或者应用的需求,或者是对产品本身的需求。基于这一点,就系统特性和提出的功能进行集体讨论,并对明显的限制条件进行检查。
需要开发一个概念性的项目定义(Conceptual definition of project)以保证项目中的每一个成员及时到位,并且明确将要开发的产品是正确的,有前途的和有益的。这个阶段包括对市场上已有产品的评估,明确现有厂商没有满足的用户需求。本阶段也可以是明确来自现有用户或者未来用户特定需求的新产品。
由于都是针对特定的用户或者市场,每种情况都需要对产品需求的初始研究,需要起草一个较高级别的建议书,列举项目必需资源和开发阶段时间计划,同时还需描述对产品期望利润的估计。这个建议书将被提交到高级管理层(Senior Management),来决定是否启动项目或者是需要向他们提供进一步的信息。
在这个阶段中将明确用户需求,确认产品的基本安全目标。本阶段必须明确产品是否进行敏感信息的处理,定义这些信息的敏感度级别(Level of sensitive)。项目需要从风险分析开始,评估威胁和脆弱性,估计不同安全对策的投入产出比。本阶段还需要解决与完整性、机密性、可用性相关的安全问题。注意每种安全属性的等级以明确需要实现的安全控制。
在风险管理过程建立之后,应该设计一个基本安全框架。风险管理将在整个项目的生命时间内持续进行。下面的一些风险信息将需要在项目启动阶段就开始进行收集,但是,随着项目阶段升级到功能设计和详细设计阶段,这些信息也需要进一步细化。
11.10.2.2 风险管理
考虑一个问题:How bad can we screw up?
风险管理阶段最重要的一个方面就是明确要提问的正确问题。
关于风险管理,曾经在第三章讨论过,但是风险管理是从整体上对影响业务的风险进行鉴别和处理。在软件开发和实施阶段尤其要进行风险的管理。尽管这两个功能在概念和目标上相似,但是它们有不同的特定任务。
对于软件开发,人们通常将注意力集中在功能性开发,并尽可能推向市场进行销售。多数情况下,安全并不是这个过程的部分,或者是在开发期限即将到来时取消安全方面的考虑。实际上,不仅程序员需要以一种安全的方式进行编码,而且产品设计者应当将安全集成考虑并在各个项目阶段分层体现,在软件工程过程中应当解决安全威胁并提出解决方案。事实上,直到一些客户购买软件之后直接由于产品开发和编码中的问题而遭受攻击并造成损失,安全一直没有被认为是产品的重要功能。在整个过程中,安全占有很重要的位置,但是在完成的项目中集成安全为时已晚,而开发和发布安全补丁程序。
风险管理的第一步是进行威胁和脆弱性的识别以及计算相关的风险。当评估出所有的风险之后,管理层应该决定能够接受的风险水平。当然,如果管理层不接受任何风险将产生最佳的安全效果。对产品而言,为了达到安全应当经过良好设计和精心测试;然而这将增加产品的开发时间和成本,因此折中的方案是在风险和经济可行性之间遵照平衡点,做出明智的业务决策。
11.10.2.3 风险分析
进行风险分析的目的是鉴别相关风险和潜在的危险后果。这个过程通常包括访谈很多问题来找出威胁细目清单,这些威胁被利用的可能性以及如果威胁发生造成损失的大小。这些威胁可能与不同产品、产品功能、实施环境、使用者个人以及购买和使用这种产品的业务类型有关。下面是在软件风险分析过程中的部分问题列表:
缓冲区溢出漏洞的可能性有多大,能够造成多大损失?
外界环境的和内部环境是否存在威胁源,是什么威胁?
什么业务类型依赖此类产品?如果在特定时间产品失效会造成什么类型的业务损失?
是否存在隐蔽通道问题需要解决?
产品中是否集成有容错机制,何时启动?
是否需要加密?需要什么类型和强度加密?
紧急情况发生时,是否有意外事件计划?
产品是否由第三方(ISP或者主机托管机房)维护?
为什么移动代码(Mobil Code)是否必需?如何处理?
产品是否处于有Internet连接的环境中?对产品有何影响?
产品是否会与存在弱点的系统交互?
产品是否会存在遭受拒绝服务攻击(Denial of Service, DoS)的弱点?
产品是否会遭受病毒攻击?
是否需要入侵警报机制?
内部员工和外部用户是否存在破坏(sabotage)产品的动机?原因和方式?
竞争机构是否会利用产品缺陷?原因和方式?
如果产品失效,会给其它系统造成什么影响?
这只是一个简短的问题列表,每一个问题都可以引出很多其它分支问题以保证所有可能的威胁和风险都能够被识别,并给予充分的考虑。
一旦识别出所有的风险,应该给出风险发生的可能性,并正确评估风险可能造成的后果,目的是为了保证对开发阶段和产品本身实施正确的安全控制措施。如果产品只是用来生成字面文档,那么就可能需要较低级别的安全措施和测试;如果产品处理信用卡数据,就需要高等级的安全防护。
在第三章中已经列出了很多相同的风险分析步骤,在开发产品时可以应用这些步骤进行风险分析。识别出风险之后,估计这些风险的可能性,计算这些风险造成影响的后果,就可以将风险按照重要性顺序进行排列。如果Dos发生的可能性很高,可能对客户造成损失,那么这个风险的重要性就很高。如果伪造的可能性较低,那么这个风险的重要性就很低。可能性最大和可能造成毁灭性损失的风险应该首先进行处理,可能性小和损失较小的风险的处理就应该排在重大风险之后进行处理。
在产品设计和体系架构中考虑产品功能、实施过程和所需的维护,同样风险也需要在其中得到解决。一个银行软件产品可能设计在组织的非军事化区(DMZ)的服务器集群中,但是部分组件和数据库服务器可能位于防火墙之后,得到另一层保护。这意味着产品体系结构可能包括不同的系统的分离以及开发系统不同部分之间的通信方法。如果产品提供安全电子邮件(secure e-mail)功能,那么就需要正确分析和考虑所有与这个服务相关的风险:用户如何准备产品?系统和环境需求是什么?产品是否需要公钥体系(PKI)?对很多产品而言,安装之后的维护是非常重要的。产品提供商是否需要和用户一起面临安全问题?是否进行日志记录和审计?在开始阶段考虑的越多,那么过程后面出现的混乱情况就可能越少。
理解项目风险分析和安全风险分析之间的区别是很重要的。很多情况下,这两周概念被混淆或者被结合到一起。项目组需要分析与项目失败相关的风险,这与安全风险分析有很大的不同。安全风险包括不同的威胁和问题。项目参与者需要正确理解和运用这两种风险分析,但是需要完全不同的方式。
11.10.2.4 功能设计分析和规划
图
在这个阶段,需要开发项目计划来定义安全行为,开发安全检查点(Security Checkpoint)来保证安全控制措施(Security Control)的质量控制以及识别配置过程和变更控制过程。在这个阶段进行资源确定、形成测试计划和评估准则来保证安全控制措施的正确测试。正式的功能基线的形成意味着以一种正式的方式,通常是文档化,勾勒出产品的期望轮廓。测试计划在每个阶段需要被更新,以保证所有的问题都被正确测试。
安全需求可以从以下几种来源得到:
系统或者应用的功能需求
国家、国际或者组织内部的标准和指南(standards and guidelines)
输出限制
被加工数据的敏感度级别(军用战略数据,还是私有区域性数据)
相关安全策略(security policy)
成本效益分析(cost/benefit analysis)结果
达到目标安全等级所需的保证度(level of assurance)
在整个项目过程当中,随着更多的信息被发现,初始的风险评估结果很可能被进一步修正。在有些项目中,在生命周期中可能需要不止一次风险分析。例如,当项目组得知产品需要在一个中等安全级别的域中对用户进行鉴别和认证,这时执行一次初始的风险分析。后来,如果产品需要工作在高安全级别的系统环境中,并与生物测定设备(Biometric devices)集成工作以满足这种需求时,就需要进行一次新的风险分析,因为系统中加入了新的部件。
功能设计分析和规划阶段解决了产品之外的功能性需求,并被记录到设计文档中。如果产品是为特定用户开发的,设计文档则被用来向用户解释开发人员对产品需求的理解。设计文档通常由系统分析员(Analyst)在工程师和系统设计师(architect)的指导下编写,并提交给用户。用户将决定是否进行功能的增加或者删减,用户和开发人员通过对话的方式仔细敲定产品的一些功能需求细节。
安全方面的问题是被提及最多的问题。这些问题包括:认证和授权是否必要?是否需要加密?产品是否需要与其它系统的接口?产品是否直接连接Internet?
许多公司跳过功能设计阶段,直接进入产品详细设计阶段。或者在功能设计阶段没有与用户进行交流。这将导致时间延误和大量重复工作,因为在进入详细设计之前需要对产品有一个整体性认识。如果用户没有参与到这个阶段,那么用户很可能认为开发者开发的产品并不是完全按照用户需求进行开发的。产品开发过程中会浪费大量的时间在非用户需求的功能开发上。因此在编码开始之前,开发就需要有明确的目标和方向。这通常也是项目管理人员的一个重要职责。
11.10.2.5 系统详细设计
图
软件需求由一些信息模型(informational model)、功能模型(functional model)和行为模型(behavioral model)得来。信息模型规定了被处理信息的类型以及如何进行处理。功能模型概括了应用程序需要执行的任务和功能。行为模型说明了应用程序在特定事务发生过程中和发生之后的状态。例如,防病毒软件的信息模型定义了处理的信息类型,如病毒特征、被修改的系统文件、关键文件的校验和和病毒行为。其功能模型规定应用程序应当能够扫描硬盘驱动器、检查已知邮件病毒、监控关键系统文件以及自我升级功能等。而其行为模型则可能说明当系统启动时防病毒软件将扫描硬盘驱动器。如果发现病毒,应用程序将改变状态,正确处理病毒。病毒发作的事件将改变应用程序状态。应当考虑每一种可能发生的状态,以保证应用程序不会进入非安全状态,或者以非预期的方式运行。
因此,信息模型、功能模型和行为模型的信息将作为软件设计的需求。结果是软件设计包括数据设计、结构设计和过程设计,如图11-12.。
图11-12 信息从三个模型中进入设计,并得出结果
数据设计利用信息模型的信息,并将其转换为软件实现所需的数据结构。结构设计定义了主要结构和不同组件之间的关系。过程设计将结构化组件转换为过程描述。
在这个阶段中需要确定访问控制机制。定义主体权力和权限,选择加密方法和算法,解决敏感数据处理问题,识别出必须的客体和组件,评估内部通讯机制,确定完整性机制,评价其它安全详细设计并定义出解决方案。
这个阶段需要确认任务分解结构(work breakdown structure, WBS),包括开发阶段和实施阶段。WBS包含测试、开发、分段实施、集成测试和产品发布等各个阶段的时限和详细活动。
系统设计是用来描述用户需求和系统内部行为的工具。它通过映射这两个方面来描绘系统如果通过内部行为完成用户需求的。
在本阶段的开始,需要考虑产品的更多细节以及产品的工作环境。功能性需求在最后确定。本阶段解决了提供这种功能所需的工作机制,决定如何进行编码、测试和实施。
产品的模块化和重用(modularity and reusability)问题,或者说产品组件问题,需要在这个阶段解决。提供关键安全功能的代码设计应该尽量简洁,以便能够以尽可能明确的方式发现错误,并尽量测试各种可能的情况。组件应该可以在产品的其它部分或者其它应用程序中调用和利用。这种可重用性可以促进产品的流水化加工(streamline),提供一个更加高效和结构化的编码环境。
在产品开发的早期阶段,可能需要处理和解决可移植性问题(portability)。如果产品需要工作在Unix或者NT系统时,那么编码需求就与只安装在一种主机上的产品不同。产品工作的环境同样需要考虑。产品是由个人用户使用,还是所有的用户都可以某种方式通过网络访问产品?多用户产品在详细需求开发时比单用户产品有更多细小的分支问题。
在早期阶段需要考虑产品和组件的可测试性,而不是在后期考虑。程序员可以开发一些钩子程序(hooks)向测试人员说明产品在不同数据处理阶段所处的状态。仅仅由于产品动作正确并在数据处理最后得到正确的结果,还不能说明没有内部错误发生。这就是测试为什么需要以模块化的方式进行,需要跟踪产品的数据流,分析每一个步骤。
在这个阶段需要进一步仔细考虑在项目启动阶段提出的问题,保证详细设计中解决了每一个问题。例如,如果需要认证,这个阶段需要设计认证过程的所有必须的细节。如果欺骗是产品最大的风险,那么就应该明确所有的对策并说明它们在产品中是如何集成的。如果隐蔽通道(covert channel)是产品的一个风险,解决这个问题就需要开发伪代码(pseudocode)来说明隐蔽通道是如何被减少或消除的。
如果产品是为特定用户开发的,产品的详细设计应当提交用户以保证所有的开发都是遵循用户需求并保持正确方向的。在进入编码之前,需要在这个阶段仔细推敲任何混淆和误解。
在设计阶段所作的决定对开发阶段而言是关键的。设计是用户需求转化为软件的唯一途径;这样,软件设计就作为整个产品开发的基础。软件质量和维护在很大程度上受软件设计的影响,如图11-13。
图11-13 如果开始没有进行良好的产品设计,那么后面的阶段将充满困难
11.10.2.6 软件开发
图
在这个阶段,程序员可开发者都需要深度参与。在前面的阶段中,他们通常是通过提供建议和指导方向参与的,而在这个阶段,就需要他们亲自工作了。编程和测试工作开始了!
在这个阶段程序员应当持一种不允许产生软件缺陷的态度进行工作。如检查输入数据长度以免发生缓冲区溢出,编程中防止隐蔽通道的产生,检查数据类型的正确性,保证检查点不会被用户绕过,语法验证,执行校验和验证等等,这些只是需要解决问题的一部分。应当测试不同的攻击情景,弄清除对代码的攻击或者以非授权的方式修改数据是如何进行的。应该由成对的程序员执行互相的调试和代码检查,一切过程都应该有文档记录。
大多数程序员不喜欢编写文档,他们往往寻找方法逃避这项任务。那么经过6个月到12个月的时间,没有人会记得解决了那些问题、如何解决的、采取何种方案解决遇到的问题,或者是解决问题的人已经跳槽到竞争对手哪里,或者是由于其它原因离职。这些是又一种造成重复工作和时间浪费的原因。基于种种原因,文档非常重要,从长远来看,它可以为公司节省大量成本。
正式或者非正式的测试应该尽快开始。单元测试(Unit testing)可以在开发早期开始。程序员开发出一个组件或者编写出一个代码单元,应该通过在各种不同的情况下输入不同的数据进行测试。单元测试通常贯穿整个开发阶段。正式测试应当由开发人员之外的另一组人员进行。这是职责分离(Separation of duties)的一个例子。程序员不能包揽软件开发、测试和发布等所有的工作。越多的人检查代码和进行测试,那么在软件发布之前发现软件缺陷的机会就越大。
职责分离(Separation of duties)
不同的环境类型(开发、测试和生产)应当被正确分离,功能和操作不应该重叠。开发者不应当访问生产过程中使用的代码。代码应当经过测试,提交到代码库,然后发送到生产环境。
当然,任何为测试或者修改目的插入的软件钩子程序(hooks)在软件发布之前都应该移除,因为这些可能会给攻击者提供进入产品的后门。
关于安全测试没有任何统一的方法,因为应用程序和产品在功能性和安全目标上有着太多的差异。重要的是把安全风险映射为测试用例和测试代码。可以遵循线性思维,识别风险之后,提供必需的测试场景,执行测试,检查代码是如何处理这种风险的,如图11-14。在这个阶段,测试应该在集成系统中进行,以模拟产品工作环境,保证代码不仅仅能在实验室正常工作。
图11-14 识别风险之后,需要开发测试场景来验证风险的解决
在这个阶段通常需要进行安全攻击和渗透测试来发现任何遗漏的软件缺陷。功能、性能和抗渗透性被进一步评价。应当将产品所有必需的功能记录在一张检查表上,以保证充分考虑到每一种功能和每一个人。
安全测试应当针对项目早期识别出的风险,如尝试缓冲区溢出,对产品进行攻击,在界面上尝试各种非期望的输入,进行拒绝服务测试,产生非正常用户行为,系统崩溃后能否返回到安全状态。产品应该在不同的环境中测试不同的应用、不同的配置和不同的硬件平台。如果产品安装在一个独立运行的全新的Windows 2000上,可能运行良好,但是如果安装到一个以SMS客户端远程网络访问的笔记本上就可能出现很多意想不到的错误。
在这个阶段的单元测试和正式测试中,会有很多问题报告给开发人员。这些问题被修补后重新进行测试。这是一个连续的过程,直到所有的人都满意并认为可以进行生产为止。如果有特定用户,那么在正式接受产品之前他将进行一系列的测试。之后,产品就可以正式发布,投放市场或者提交给用户。
11.10.2.7 安装和实施
图
实施阶段着重如何使用和操作开发好的系统或者应用。
在这个阶段,用户已经购买了开发好的产品,并安装到工作环境中。产品需要进行配置到一个正确的保护等级。通过执行功能和性能测试并进行结果分析,验证产品是否满足用户的安全需求。
系统配置应当被记录到文档中。开发用户指南和运行维护手册以使用户知道如何正确使用系统,使技术人员知道在需要时如何正确配置产品。需要监视安全活动以保证系统或应用以服务水平协议(Service Level Agreement, SLA)保证的方式运行。
认可(Accreditation)应当在开发之后,系统应用开始运行之前进行。这个过程需要遵循认证过程,认证过程正式或者非正式地测试所有的安全特征,以确认产品是否完成所需的安全功能。认证(Certification)是一个检查和评估安全控制的过程,通常由外部独立的机构执行。(认证和认可在第5章中已经详细介绍)
认可是管理层对系统的正式接受,也是明确的对风险的接受。认可考虑整个系统,而不仅仅是一个应用或者一个新更新的特征。这是因为安全不是一个划分性质的属性,而是一个在系统各层次上的服务,并可以多种方式证明。认可过程迫使管理层和技术人员共同工作以保证质量和由购买并实施的技术提供的保护等级。技术人员了解运行和机制上的问题,而管理层理解任务、财务和可靠性问题。在认证过程中他们共同覆盖了大部分问题。
一旦确认新系统提供的安全功能并且理解和接受残余风险(Residual risk),管理层应当发布一个正式的认可声明。
应当打开审计功能并监视事故恢复计划(Contingency recovery planning),开发响应程序并进行训练以保证系统和产品在系统故障和紧急情况下能够正确反应。
11.10.2.8 运行和维护
图
运行和维护阶段中安全工作并没有完成或者说安全在控制之下,也并非无事可作。相反,安全在这个阶段比先前其它阶段更重要。
这个阶段开始部分的工作包括新系统的配置,将其正确安装在网络和工作环境中。很多情况下,安全功能并没有被打开或者没有为当前环境进行正确配置。因此,即使从产品开发开始就进行正确地编码,也不可能考虑安全功能不被使用或者无人负责的情况。
运行保证(Operational Assurance)通过以下活动执行:进行弱点测试、系统行为监控、事件审计。正是通过这些运行保证活动管理员才了解新的弱点和安全危险,以及时采取正确的行动。
如果系统、产品或者环境发生重大变化,那么就需要进行一次新的风险分析和新的认证和认可过程。这些重大变化包括增加新的系统或者应用,设施搬迁或者是数据敏感性和关键性的变化。
11.10.2.9 处理
任何好的事物都有结束。
图
当系统过期或报废时,应当采取一些新的恰当的步骤保证事务过程以安全的方式进行。根据系统中数据的敏感等级,应该采取不同的处理方式。信息可能需要存档、备份到另一个系统、废弃或者完全破坏。如果敏感信息需要完全破坏,可以通过覆盖清除、消磁(degaussing)或者物理破坏存储介质。敏感信息的处理方式需要依据数据本身和组织的安全策略。
11.10.2.10 事后回顾(Postmortem Review)
对项目组来说,项目完成后收集信息、回顾整个项目的过程、讨论下次项目应该改进的问题是很重要的。如果认真执行事后并正确处理,组织在后来的项目中可以节省成本,因为吸取了以前项目中的教训,同类错误不会再发生,项目过程也被简化。所有这些活动将帮助下一个项目以更少的错误和更短的时间顺利进展。
事后回顾应该是有组织的活动,有人主持会议和进行记录,但对每一个成员应该有宽松和谐的气氛以使他们更好地表达他们的观点和想法。重要的一点是会议不应该成为指责和抱怨的场所。这是一个从客观的角度考虑项目,发现下次可以改进问题的很好的途径。
有的组织看不到事后回顾的价值,只是结束一个项目紧接着进入下一个项目,很可能又会遇到先前项目中的问题。项目是一个不断学习的过程,其职责是以最短的时间和最低的成本制造出最好的产品。理解这两点的结合,使事后回顾成为每个项目的一部分,这对管理层来说是有益的。最成功的情况是能够简化项目过程和项目管理,使之成为一个能够达到期望质量等级的可重复过程,然后继续考虑项目如何改善和进一步积累。
图11-15 本章阐述了一个包含七个阶段的生命周期。其它模型可能使用不同的周期和不同数量的阶段,但是都是完成同一件事情
项目启动
项目定义的概念
建议书和最初学习
功能设计分析和规划
发现并定义需求
定义系统环境规范
系统详细设计
功能设计检查
功能分解
详细规划
代码设计
软件开发
软件开发和编程
安装
产品安装和实施
测试和审计
支持维护
产品变更、修补和小的修改
修订和代替
修订产品或者完全替代
11.10.3 变更控制(Change Control)
如果没有正确处理,开发和生产过程中的变更可能造成大量混乱。发生变更有几种原因。在开发阶段,用户可能会改变需求,增加、删除或者修改某些特定的功能。在生产阶段,变更可能会由环境改变造成,如对产品或系统的新的需求或新发布的补丁程序或者升级升序。这些变化应当被严格控制以保证每个变更都被批准、正确合并以及不会对原来的功能造成副面影响。配置管理(Configuration management)是控制产品生命周期和记录必要的变更控制活动的过程。
在项目的开始阶段就应该做好处理系统变更的准备,每个人都知道如何处理变更以及有变更需求时每个变更入口点的期望值。有些项目从开始就注定失败,因为项目没有制定和实施正确的变更控制策略。很多项目在开发阶段中,用户和开发者签订关于产品需求、规划和详细设计的备忘协议。客户需要签订一个合同表示同意这个协议,并且如果以后发生任何需求变更,客户需要支付由开发者的额外工作引发的成本。如果没有这种保证,客户需求会不断变更,开发人员需要付出大量的工作应付这些变化,造成成本增加,而产品开发日程也会受到影响。
变更控制(Change Control)
变更必需被授权、测试和记录。发生变更的系统可能需要重新认可和认证。
还有其它原因会需要变更控制,这些原因涉及组织、标准流程和期望结果。如果产品处于开发的最后阶段,这时有一个变更需求,开发组应该知道如何处理这种情况。通常开发经理必须通报项目经理如果引入变更会需要多少额外的工作量,应该采取哪些步骤保证变更不会影响产品中的其它组件。此外,安全不能遭到破坏,变更必须由管理层批准。如果这些过程得不到控制,开发队伍中一部分人员实施变更,而另一部分人对变更一无所知。实际上这将影响他们的工作。当他们分工的工作集成在一起的时候,会发现他们的工作出现矛盾,工作将不会得到肯定,因为管理层开始并没有批准变更。
变更必须经过批准、记录并且测试。有的测试可能需要从新运行以保证变更不会影响到产品的功能。当一个程序员改变源代码时,这种改变应该在代码的测试版本上进行。对源代码的变更绝对不能在代码的生产版本上进行。发生变更的代码经过测试进入代码库中。生产代码只能从代码库中得到而不能从程序员或者测试环境中得来。
在系统审计过程中必须对变更控制进行评估。在测试中很可能忽略由变更引起的问题,因此在系统审计中必须对变更控制如何实施和执行的过程进行检验。
下面是变更控制过程的一些必要步骤:
² 提出正式变更请求
² 分析变更请求
n 开发实施策略
n 计算实施成本
n 检查任何安全问题
² 记录变更请求
² 提交变更请求要求批准
² 变更开发
n 记录产品程序段,增加或者删减功能
n 关联变更和与正式变更控制请求相关的代码
n 提交软件进行测试和质量检查
n 重复以上过程直到质量合格
n 完成版本变更
变更控制和安全
变更控制需要保证安全策略仍得到正确贯彻,并且安全机制不会受到副面影响。
对系统的改变可能需要新一轮的认证和认可。如果系统发生重大改变,功能和保护等级可能需要重新评价(认证),管理层需要重新批准包含新的变更的整个系统(认可)。
11.11 应用开发方法学
应用程序是由程序代码编写的,这些代码使操作系统和硬件在执行应用程序时完成用户需求的功能。程序语言经历了几代变化,每一代语言都是建立在以前的基础上,提供了更丰富的功能,在发展过程中为计算提供了更多的选择。
编程语言有几种类型:机器语言(Machine Language)、汇编语言(Assembly Language)和高级语言(High-level Language)。机器语言是计算机和处理器可以理解的语言,可以直接执行。汇编语言和高级语言不能直接被系统理解,必须经过处理转换为机器语言。这个处理过程通常由编译器(Complier)完成,编译器将人易于理解的编程语言转换为机器可理解的语言或者目标代码(Object code)。
当用户购买程序时,通常是机器语言的形式。程序已经经过编译,可以在系统上进行安装和执行。编译器将代码转换为特定处理器可以识别的形式。这就是为什么有的程序可以在Alpha处理器的计算机上执行而不能在Pentium处理器的计算机上执行。不同的处理器需要不同形式的机器语言。
如果程序以源代码形式出售,必须在用户的计算机进行编译,这样用户必须拥有相应的编译器。当然,源代码也可能会向竞争对手泄漏设计思想和技术。
有几种类型的程序可以将高级语言(或源代码)转换为机器语言(或目标代码),它们是编译器(Complier)、汇编程序(Assembler)和解释器(Interpreter)。它们以翻译的形式进行工作。解释器在执行过程中逐条翻译命令,编译器一次编译一大段代码,而汇编程序将汇编语言翻译成机器语言。多数程序是经过编译的,而很多脚本语言程序是解释执行的。图11-16解释了它们之间的关系。
图11-16 在将源代码翻译成目标代码的过程中可以使用不同类型的程序
编译和解释
解释程序拥有可以读取和一次解释一条指令的程序。这个程序——解释器(Interpreter)实时地将高级语言指令转换为机器可读形式。
编译程序由高级语言编写,由编译器(Complier)将其转换为机器可读形式。
11.11.1.1 面向对象的概念
过去,软件开发通常使用传统的输入-处理-输出(input-processing-output)方式。它使用由层次信息结构而来的信息流模型(information flow model)。向程序输入数据,程序将数据从头传到尾,执行逻辑程序,返回结果,如图11-17。
图11-17使用非面向对象的方法编程,通常从程序开始输入数据,得到结果后输出
面向对象的编程方法(Object-oriented programming, OOP)以一种有效的方式使用不同的技术执行同样的过程。首先,应该理解面向对象编程(OOP)的基本概念。
OOP使用类(Class)和对象(Object)的概念。实际中的对象,如一张桌子,是一个叫做“家具”的一大类对象的一个成员(member,或者实例-instance)。这个类拥有“家具”类中每一个对象相关的一组属性。这些属性可能是颜色、几何尺寸、重量、样式和成本。这些属性的对象可能是椅子、桌子、双人沙发等。因为桌子是“家具”类的一个车工能源,因此桌子继承了这个类中定义的所有属性,如图11-18。
图11-18属于类的每一个对象拥有该类的所有属性。这种方法提供了一种模块化和组织化的编程和设计。
一旦一个类被定义,那么每一个由这个类创建的新成员或者新实例都可以重用这些属性。当对象应用一个操作或方法(method)时,属性可以被修改。如果对象椅子被漆成紫色,那么方法就是油漆这个动作,新的颜色属性值就是紫色。方法是对象被操作的方式。如图11-19所示。
图11-19属于类的每一个对象拥有该类的所有属性。这种方法提供了一种模块化和组织化的编程和设计。
注意:在面向对象编程中,对象是由相关类提供的模板定义的唯一的实例(Instance)。
下面看另一个关于银行顾客的例子。顾客Cheryl Craig是顾客类的一个成员。这个类的每一个成员都拥有如下属性:姓名、地址、电话号码、账户余额。当Cheryl从ATM机中取款$40,她的银行账户余额就会减去$40。这个行为就是影响账户余额属性的方法。这些方法被预定义为可接受的行为并从类中继承而来。见图11-20。
图11-20对象继承属性和方法,是对对象数据操作的可接受的行为
对象对属性值进行封装,意味着信息被封装,以一个对象名字的名义可以被其它对象看作一个整体进行重用。对象之间需要能够互相通信,这通过使用消息(message)完成。如果对象A需要告诉对象B Cheryl的账户需要减少$40,它将向对象B发送一个消息。这个消息由以下部分组成:目的、需要执行的方法以及相关参数。如图11-21。
图11-21 对象之间通过消息进行通信。消息格式:目的、需要执行的方法以及相关参数。
一个对象可以有公共部分和私有部分组成。公共部分是对象与其它组件交互的接口。消息通过这个接口进入对象并指明要执行的操作请求或方法。对象的私有部分是对象实际如何工作和执行这些请求的操作。其它组件无需知道每个对象内部如何工作,只要提出请求的工作即可。这就使得信息隐藏(Information Hiding)成为可能。处理的详细信息对此对象外的其它程序元素是隐藏的。对象间通过定义好的接口进行通信,因此不需要互相知道其它对象的内部工作机制。
注意:封装(Encapsulation):数据隐藏由封装提供,保护外界不能访问对象的私有数据。对象不必允许其它对象访问自己的内部数据和处理过程,也不需知道其它对象的内部数据和处理过程。
一旦定义好对象,就有必要开发分级结构(Classification Structure),即定义和命名一个对象的实例。如果主要对象命名为Dog,那么这个对象相关的下面三个对象可能是Labrador、Terrier、Bulldog。图11-22描述了这些对象之间的关系,给出了分级关系并定义了对象之间的关系。结构化表示是分离模型需求的一种方式。
图11-22 分级结构可以更好地组织对象之间的关系
这些对象可能会增长到很大的数目,因此理解、跟踪和分析对象的复杂性是最大的问题。在文档中,多数情况下对象以参考(reference)和指针(pointer)连接的形式表示。图11-23展示了在ATM系统中相关对象以特定块和参考来表示。这使得分析员和开发者从更高级别的操作和程序角度看待一个对象,而不需考虑每一单个的对象。这种模块化(modularity)提供了一种更易于理解的模型。
图11-23 拥有很多对象的程序变得异常复杂。它们通常用参考(Reference)表示,指向几个不同的对象,显示应用程序自身的主要功能。
抽象(Abstraction)是忽略非必要的细节而只关注重要的内在特征的能力。抽象使得系统在概念上分隔。例如,如果软件设计师需要理解程序中的数据流,他像要理解程序大的模块并且从输入到输出对数据进行逐步跟踪。如果涉及到每个程序模块的细节就很难弄清数据流的概念。然而通过抽象,他可以忽略所有的细节问题而理解产品的关键部分。
消息可以通过几种方式发生。两个对象可以存在单向(一对一)的连接,也可以有多向(一对多)的连接,可以是强制连接或者非强制连接。重要的是映射出这些通信路径来确定信息是否按照预期的方式流动。这将帮助设计者保证敏感数据不会向低安全级别的对象传递。
每一个对象都有其应遵守的规范。这个规则保证了简洁的编程,减少了编程错误和遗漏。下面的列表是一个每一个对象应该开发的内容:
² 对象名称
² 属性描述
n 属性名称
n 属性内容
n 数据类型
² 外部输入
² 外部输出
² 操作描述
n 操作名称
n 操作接口描述
n 操作过程描述
n 性能问题
n 限制和约束
² 实例连接
² 消息连接
每个对象都可被重用(Reuse),这正式OOP的优点。对象重用使得资源的利用和程序员的工作更有效率。不同的应用程序可以使用同一个对象,减少了重复性工作。如果应用程序的功能增加时,很容易增加一个对象并集成到原来的结构中。
对象可以被编译到库(Library)中,为其它应用调用对象提供了一种简便的方式(如图11-24)。库提供了对象在系统内或者其它系统中位置的索引和指针。
图11-24 应用程序可以通过组件库中的索引访问和重用组件
当以如面向对象方法等模块化方法(Modular approach)进行开发时,组件可以被重用,复杂性被降低,并可以开展并行开发。这些特点使得开发减少了错误,更容易修改,资源利用更有效率,比传统的信息流模型开发更容易控制开发时间。OOP还提供功能独立性,即针对某个特定子功能需求的每个模块都有一个接口,很容易被程序的其它部分理解。
对象封装意味着数据结构、操作功能和可接受的访问方式被组装到一个实体当中。其它对象、主体或者应用程序可以通过以可控的标准方式向接口发送消息来使用这个对象和其功能函数,如图11-25。
图11-25 对象的不同的组件和其工作方式对其它对象而言是隐藏的。只要存在明确的通信接口,就不需要知道其它对象的工作机制。
面向对象的设计(Object-oriented design)建立了真实问题的表述并将其映射到软件方案中。这种设计将数据对象和处理操作连接在一起。其编程方法不同于其它方法,因为它允许抽象、模块化和信息隐藏。(信息隐藏(Information Hiding)在“面向对象的概念”一节中已经做了解释)。模块化由对象使用、Java小程序(Applet)和接口进程(agent)完成。
注意:面向对象的编程(OOD)是使用一组相关的对象集合进行系统建模的设计方法。每一个单独的对象都被看作是类体系中某个类的一个实例。
多态(Polymorphism)
多态为对象行为增加了另一种功能,可以帮助为对象提供更好的描述。多态指的是对象对消息的响应是由对象所属的类决定的。属于不同的类的对象可以用统一的方式处理,但是它们却表现出不同的行为。
下面看一个关于多态的简单例子,三个不同的对象接受同一个输入“Bob”。对象A经过处理后输出“43-yeal-old white male”,对象B输出“Husband of Sally”,而对象C输出“Member of User group”。每个对象接受同样的输出,但是却以不同的输出进行响应。
面向对象的分析(Object-oriented Analysis,OOA)是将对象分类并使之适于方案的过程。通过对问题的分析来决定应用程序使用的对象所属的类。
OOD使得工程师或者开发人员指出从每个类中得出的对象以及这些对象如何协同工作。因此这些问题需要被分析,并提出一个解决方案。然后再进一步推敲方案的细节。
OOP是一类基于对象的概念和一组用于数据操作例程和方法的编程语言和技术。下面是OOP的一些特征:
² 封装(Encapsulation) 隐藏内部数据和操作
² 多态(Polymorphism) 复制对象并在这些对象中造成变化
² 多实例(Polyinstantiation) 对象中数据之间的的明显区别,为了避免低安全等级的主体访问高安全等级的信息
² 继承(Inheritance) 共用特征和属性
11.11.1.2 数据建模(Data Modeling)
在前面的章节中,我们对结构化分析方法(structured analysis approach)有了简单的了解。一个完全的结构化分析方法需要考虑所有的对象和应用程序的主体,映射它们之间的内部关系、通信路径和继承特性。这不同于数据建模(Data Modeling)。数据建模独立地考虑要处理的数据和处理数据的组件。数据模型需要从头至尾跟踪输入数据,并且验证输出的正确性。OOA是一个结构化分析模型方法的例子。如果分析员检查应用程序的OOA,他将证实建立的所有关系的正确性:继承遵循预定义和可用的方式;对象实例可行并且提供必需的功能;每一个类的属性覆盖了应用程序使用的所有值。当另一个分析员进行数据建模检查时,他将跟踪数据并在数据处理后检查返回值。一个应用程序有完美的OOA结构,但如果1+1的处理结果是-3,那么肯定某处出了问题。这就是数据建模所分析的内容。
注意:继承意味着对象从另一个对象自动获得功能函数和数据
另一个数据建模的例子是关于数据库的。数据建模可以用于提供对数据和控制数据的关系的洞察。一个文件结构中的数据项或者存储的数据可能是另一个文件结构的指针,或者不同的存储数据。重要的是这些指针指向正确的位置。数据建模将验证这一点,而OOA结构分析却做不到。
11.11.1.3 软件体系结构(Software Architecture)
软件体系将组成软件方案的组件与真实世界中的问题关联起来。程序员注重数据结构、编码规则、变量和对象间的通信路径,而软件体系结构从更高的角度考虑软件应用程序如何实际满足和完成识别出的需求,并在设计阶段符合这一点。
软件体系结构包括将需求分隔成可以由单个软件方案解决的独立的问题的过程。这个过程是在软件需求分需分析和组成最后应用程序的实际组件之间进行转换的过程,如图11-26。
图11-26 软件体系结构考虑真实的问题,并将其分解为可以由软件组件解决的子问题
如果应用程序的需求是扫描硬盘驱动器和邮件消息以查找病毒,那么软件设计师将这个需求分解为多个独立的可由应用程序功能完成的需求单元。这些需求单元包括:
² 病毒特征存储
² 比较硬盘驱动器上的软件特征串和病毒特征
² 在用户读取邮件之前解析邮件消息
² 如果必要,执行处理压缩硬盘驱动器的程序
² 如果找到病毒执行的动作
² 如果遇到加密邮件附件应执行的动作
这种产品开发方式提供了更多的可控的和模块化问题和方案。如果一个程序开发小组被告知开发一个防病毒软件包,小组将可能会像被捕的麋鹿一样不知所措。然而,如果通知一个开发者开发特征升级文件,另一个开发如何比较硬盘软件字串和病毒特征,还有一个需要开发读取压缩文件的方法,那么这些程序员就有了明确的开发目标并开始设计和编码。
软件设计师需要提供这样的方向:即对应用程序目标和项目总体目标的较高角度的考虑。
11.11.1.4 数据结构 (Data Structure)
数据结构是对数据元素之间逻辑关系的表示。数据结构指明了元素间关联的程度、访问方法、处理选择和数据元素的组织。
数据结构可能事实上很简单,如一个计数器,表示一个可由标识寻址的单个元素,可以由内存中的单个地址访问。计数器组合成数组,可以通过索引进行访问。其它数据结构包括使用多向链表(Multilinked list)的层次结构(Hierarchical structure),这些链表包含计数器、矢量和可能的数组。层次结构提供分类(Classification)和联合(Association)。如果一个用户向应用程序提出查找所有关于安全的计算机书籍,应用程序返回一个列表,这个应用程序使用的就是某一类型的层次数据结构。图11-2 |
cissp-应用和系统开发
thanks |
cissp-应用和系统开发
谢谢,不错。 |
| |