第八章程序安全与数据库安全密码技术,安全协议,计算机病毒防治注意和考虑程序级安全。作为对程序安全的一个威胁是计算机病毒,除此之外还存在更多的威胁程序安全的问题。主要有:具有安全隐患的编辑错误,如缓冲区溢出,不完善的访问控制;恶意代码:计算机病毒,蠕虫,特洛伊木马;对于程序中本身的缺陷如何避免和消除,在有问题的情况下,如何尽可能保护资源?程序缺陷分为:有意缺陷和无意缺陷两类,有意缺陷又分为:恶意缺陷和非恶意缺陷两类8.1非恶意的程序漏洞1.缓冲区溢出缓冲区溢出就好像是将大杯水倒入小杯中,肯定会有部分水流出而导致混乱。缓冲区(或数组,字符串)是存储数据的空间,位于内存,它们的容量都是有限的,因此在程序中必须定义缓冲区的昀大容量,以使编译器留出所需空间。执行过程中,所有程序和数据元素都在内存中,与操作系统、其他代码和常驻共享内存空间,造成四种溢出后果:1)额外字符溢出到用户的数据空间,则仅覆盖已存在的变量值(也可能放在未使用的位置),影响程序的运行的结果,不影响其他程序或数据2)额外字符溢出到用户的程序区域,若覆盖了已执行命令且该命令以后也不再运行,则没有影响;若覆盖了未执行命令,就可能因非法指令而停机。3)额外字符溢出到系统的数据空间,则仅覆盖已存在的变量值(也可能放在未使用的位置),影响程序的运行的结果,但不会影响其他程序或数据4)额外字符溢出到系统的程序区域,若覆盖了已执行命令且该命令以后也不再运行,则没有影响;若覆盖了未执行命令,就可能因非法指令而停机。所有的程序都是被操作系统所调用,并且操作系统的运行权限比常规程序高,若能通过伪装成系统程序就可以获得较高权限执行系列命令。攻击者通常会设法造成溢出到系统空间,由此替换系统空间中的代码,这样在其过程调用返回时就可以替换一些指令从而控制操作系统。利用堆栈指针或返回值的寄存器。子过程的调用是通过堆栈来管理的,堆栈后到先出.好处是过程调用保存在其中,并且每次调用返回都会将控制权交回给调用前的入口。由于在子过程运行时,在堆栈指针所指向的地址中找到并取出参数。攻击者可以通过造成堆栈溢出来改变旧堆栈溢出(即改变过程调用环境)或改变返回地址(这将造成子过程调用返回时,攻击者可以将控制权移交到任何地方)。攻击者可以将程序的执行重定向到他所希望执行的代码处。一种溢出是在参数值传递到程序中时发生的。=(808)-555-1212&parm2=2004jan02这里userinput页面收到了两个参数,值为:(808)-555-1212和2004jan02调用者的浏览器将接受用户从表格中填写的数值,并加密后传送给服务器。攻击者若输入一个非常长的电话号码,例如500位。开发者通常只分配了15或20个字节。若500位后,是否会由此造成程序的崩溃?如果崩溃,将是怎样的?是否可以被按照预定的崩溃的方式进行?攻击者通常是利用溢出先造成系统的崩溃,然后制造出可控制的故障,从而导致了系统的严重安全隐患。所以必须重视缓冲区溢出问题。2.不完全验证=(808)-555-1212&parm2=2004jan02如果parm2提交的值是1800Feb30或2048Min32将会造成什么后果?对于不正确的数据系统尝试处理,可能会造成系统故障,或者照常运行而得出错误的结果,如帐单计算,就会出错。采用对提交数据正确性检查,或者通过下拉列表选择,从而避免用户有意或无意的破坏。但是,提交的结果昀终是包含在URL中进行传递的,而用户特别是攻击者完全可以操作或更改URL的,而服务器是无法区分该条信息是来自客户端的浏览器还是用户直接编辑修改的URL的,因此,如果提交的数据不进行完善的验证,敏感的数据将处于公开或失控的状态。电子商务网站,用户可以直接在网站上下订单。物品,价格等。如某物品555A单价10元,购买20个,再加上运费共205元,系统将所有这些信息再显示的同时全部传回去:=101&part=555A&qy=20&price=1&transportcost=5&total=205攻击者可以通过URL将价格数值从205改到25,。攻击者可以用此方式以任何价格订购物品,直到漏洞被检查出来。漏洞何时被检查出来。如果全世界的人都用此法蜂拥而至此公司购物,那公司将马上发现问题。但个别用户,只要公司没有感到利润的明显下降,就很少会被发现,直到某天核账。运行的代码中还有多少类似的隐患?解决的方法是对浏览器产生的信息增加有密钥的信息鉴别,使得他人修改后无法产生相应的鉴别码。3.“检查时刻到使用时刻”的漏洞一位顾客购买物品,检查了该物品后,即包装后去柜台付款,回来后将凭证交给营业员后拿着物品回家。在进行检查后到拿走之前这段时间,情况可能发生变化。在计算机系统中同样有可能会发生类似事件。由于现代处理器和操作系统为了提高效率经常改变指令和程序的执行顺序,相邻指令在执行时不一定是相邻的。如果有一个访问修改请求:“将第4位改为A”。经过检查通过并被授权放入到操作队列中。由于已经被检查过,在以后调用时就不会再检查,而此时在排队过程时将此命令改为“删除某文件”,则将造成严重后果。这就是所谓“检查时刻到使用时刻”的漏洞阻止此攻击的方法是数字签名和鉴别。为了防止私钥泄露而造成后果,就可通过PKI的密钥撤销列表来解决。4.三种漏洞的联合使用攻击者可能会利用缓冲区溢出来破坏机器上的运行代码,同时利用“检查时刻到使用时刻”的漏洞来添加一个新的系统用户。然后以新用户的身份登录系统并利用不完整的参数检验漏洞来获得一定权限或做其他破坏系统的事情。8.2恶意代码恶意代码可以看成为系统中的潜伏者,是以破坏为目的的一类程序,它可能是正在运行的程序的全部或部分,由代理编制。所谓代理是指,编写该类程序的作者,或是将程序引入系统的人有些恶意代码具有传染性,即为计算机病毒,而某些则不具有传染功能,即该系统受到攻击植入了恶意代码后,该系统不会传染给其他系统。下面主要讨论不具有传染性的恶意代码。1.陷门陷门trapdoor是通往某个模块的入口,在文档中没有该入口的记录。陷门在代码开发期间加入,其目的可能是为了测试软件模块,或为将来模块的修改和功能增强提供hook(钩子),或作为系统失效时提供的一个特别通道。当程序成为产品后,陷门可使程序员进入程序。例如:通常采用系统的、有组织的、模块化的方式进行开发和测试一般,系统的每个小组件昀先测试,即所谓的单元测试(unittesting)确保每个小组件自己能正常运行。然后组件被集中起来测试,即集成化测试(integrationtesting),测试目的是看是否能顺利地相互传递信息、数据等。一般不会对组件的所有可能组合进行测试,而是合理地将一些组件聚集成一个组,通过对每个组的测试,来了解其中某个组件的故障及原因。为了独立测试组件,开发者或测试者不能按常规配置输入输出设备。引进stub和driver,作用是从被测试的组件中插入数据和导出结果。这些stub和driver将被抛弃,取代它们的将是功能与之类似的实际组件。在单元测试和集成化测试时,总会发现组件的错误。有时错误的原因不明显,需要在可疑模块中插入一段调试代码。强迫组件显示一个中间结果,或打印出组件运行步骤,或执行额外运算以验证上一个组件的有效性。为了控制输出代理或调用调试代码,特别是为了支持测试,通常程序员会在组件中嵌入特殊的控制序列。如,一个文本格式系统中有一个组件,其用途是识别.PAGE,.TITLE,.SKIP之类的命令行。在测试过程中,程序员可能会调用调试代码,使用带有一系列参数的命令,格式为var=value。该命令允许程序员在程序运行期间修改程序内部的变量值,它可以用来测试组件的正确性,也可以用来为组件提供参数值。在模块中插入命令行是认可的测试的手段。但在测试完毕后,仍将命令行留在模块中,就可能成为陷门,象蠕虫就是利用电子邮件中的调试陷门进行传播的。拙劣的“错误检查”则是产生陷门的另一个原因。一个好的开发者在设计系统时,会在每个数据使用前检查该数据,这种检查包括确保数据类型时正确的,数据值在允许的范围内。但在拙劣的系统中,一些不允许接受的数据也能轻易通过检查,并以难以预料的方式使用。某组件代码功能是检查数据是否为三种期望数据中的一种,如果数据不在这三种范围之内,就确认为一个错误;程序员使用case语句来完成上述检查过程,当三个case语句都不匹配时没有打上错误标记。Morris蠕虫所利用的fingerd漏洞就是由于类似的失误而造成的:C语言的输入输出库中的一个例行程序,在返回一个指针到下一个假定字符前,没有去检查输入缓冲区中是否有字符。硬件处理器设计是这类安全漏洞的另一个常见例子。通常出现的问题为:不是所有的二进制操作码都与机器指令相匹配。未定义操作码有时会执行特定的指令,这可能是因为测试处理器的需要,也可能是设计者的疏漏。未定义操作码在硬件中的地位与软件设计中的拙劣错误检查是相似的。陷门并不一定是恶意的,在找寻安全漏洞时,它们也是非常有用的。有时审计器需要利用产品程序中的陷门,插入一个编造的但是可标识的事务到系统中去。然后审计器在整个系统中追踪这些事务的流通过程。但是,必须在文档中很好记录这些陷门,并且严格控制对它们的访问,并且使用者必须清楚理解其内在的逻辑关系。陷门在产品中出现的主要原因如下:开发者忘记去掉陷门出于测试或维护目的而特意将其保留在程序中将它作为一个隐蔽的访问方式而特意留在程序中。要说明的是,除非开发者为了攻击系统而预留陷门外,陷门本身没有错,它只是用来调试、修正、维护程序的技术。但是如果没有警惕陷门的存在,或没有去注意阻止和控制,就将成为系统脆弱的漏洞。利用陷门的人可能是开发者,也可能是无意或有意的发现者。当自以为他人不会发现这个漏洞时,系统其实是不安全的。2.腊肠攻击就是将一些不合乎逻辑的数据位结合在一起而产生惊人的效果。如计算税金的程序在计算过程中,往往会忽略一些金额很小的款项。这样的程序就容易遭受腊肠攻击。从每个计算过程中抽取的小金额款项可以在其他地方被重新累加,如在程序员银行账户中。在计算过程中抽取的金额是非常小的,很少会引起注意,而且账面上的总收支是平衡的。但累加的金额通常会很大。例如:银行利率为6.5%,每月都要计算一次。若在一个月后,账户中余额为102.67元,计算利率方式是:对有31天的月份是将年利率除以365得到每天的利率,然后乘31得到该月的月利率,则该月利息为(31/365)×0.065×102.87=0.5495726.应该支付0.55元,但如果支付0.54,则通常储户不会很注意,而这1分就可以被程序员截留,进一步如果仅支付0.50元,则储户可能认为按角为单位,则可截留5分。公司提供服务为15元,而程序可以将此服务价格记录为20元,如果没有被查到,则多出的5元就被截留。由于很大数字与很小数字相结合的时候,容易受到舍入错误的困扰。系统规模和检查漏洞的代价成了恶意代码程序员的帮手。3.隐蔽通道——泄露信息的程序传送信息的通信方式是隐蔽的、与其他方式同时进行,并且是非常合理的,称这些特殊的通信路径为隐蔽通道如,在考试时,形式为选择题,4选1,约定作弊方式是,咳嗽表示选A,叹气表示选B,打哈欠表示选C等等,监考人难以知道其作弊使用的通信方式,这就是隐蔽在公开的通道里的(咳嗽,叹气,打哈欠)。直接访问数据的程序员通常仅需要读取数据,将数据写入到其他文件或打印出来。若程序员的权限排除在访问数据之外,其如想获得这些信息,就设计一个内藏特洛伊木马的程序,一旦木马启动,该程序就会寻