代码安全研究.docx

上传人:b****8 文档编号:27643656 上传时间:2023-07-03 格式:DOCX 页数:32 大小:93.13KB
下载 相关 举报
代码安全研究.docx_第1页
第1页 / 共32页
代码安全研究.docx_第2页
第2页 / 共32页
代码安全研究.docx_第3页
第3页 / 共32页
代码安全研究.docx_第4页
第4页 / 共32页
代码安全研究.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

代码安全研究.docx

《代码安全研究.docx》由会员分享,可在线阅读,更多相关《代码安全研究.docx(32页珍藏版)》请在冰豆网上搜索。

代码安全研究.docx

代码安全研究

 

目录

摘要1

关键词1

Abstract1

Keywords1

引言1

1代码安全存在的问题2

1.1重大代码安全问题案例2

1.2何谓代码安全3

1.3存在代码安全问题的原因3

1.4不安全代码造成的后果5

2软件的安全漏洞5

2.1缓冲区溢出6

2.2SQL注入9

2.3跨站脚本(XSS)漏洞9

2.4文件访问漏洞10

3代码安全的意义11

3.1不安全的代码容易受到攻击11

3.2不安全的代码容易引发系统崩溃11

3.3修复安全漏洞的代价高昂11

4如何编写安全代码12

4.1思想观念12

4.2技术因素13

4.3编程技巧15

5结束语16

致谢16

参考文献16

代码安全研究

网络工程专业学生鲁凤伟

指导教师吴俊华

摘要:

深入研究代码安全问题。

首先是对代码安全问题典型案例汇总、分类,并描述了安全代码的明确定义,其次说明不安全代码会严重影响人们的现代化生产、生活,并进一步详细描述了软件安全漏洞----缓冲区溢出、SQL注入、跨站脚本漏洞、文件访问漏洞。

在此基础上分析了安全代码的重要意义,如容易受到攻击,引起系统漏洞,以及修复所需的高昂代价。

进一步阐明为维护互联网的安全必须从思想和技术两个方面出发编写安全代码,最后对代码安全的应用做出展望并对全文进行总结。

关键词:

代码安全漏洞互联网安全

ASurveyoftheCodeSecurity

StudentMajoringinNetworkingEngineeringLuFengwei

TutorWuJunhua

Abstract:

Codesecurityhasbeenresearched.Firstofall,typicalcasesofcodesecurityareconcludedandthedefinitionofsecuritycodeisdescribed.Secondly,itisgeneralizedthattheinsecuritycodewouldinfluenceseriouslypeople’slifeandmodernproduction.Next,theloopholesofsoftwaresecurity(bufferoverrun,SQLinjection,crosssitescript,fileaccess)areintroducedindetail.Then,thesignificancesofcodesecuritysuchasliabletobeattacked,causingsystemloopholesandexpensivecostofrepairingareanalyzed.Andthen,itisindicatedthatsecuritycodeshouldbecompileddependingonbothconceptandtechnologyinordertomaintainthesecurityofnetwork.Finally,theapplicationofsecuritycodeinthefutureisimaged.

Keywords:

codesecurity;loophole;networksecurity

引言

当前,黑客的攻击活动日益猖狂、世界著名网站屡屡被黑客攻击,网络安全问题日趋严重,信息安全成了人们最关心的话题。

如何保护自己不被网络上的其他非善意的用户攻击备受人们的关注。

传统的避免网络攻击的方法不外乎提高自己的警惕、依靠杀毒软件和防火墙。

但是时刻以高度警惕的心情享受互联网带给我们的便利是不现实的。

杀毒软件、防火墙在攻击防范中也不是万能的:

例如还未升级的杀毒软件无法发现新病毒、安全漏洞的发现速度越来越快、防火墙渗透率越来越高等。

以前人们是从用户的角度来考虑安全问题—想法设法保护用户,但未站在开发者的角度来思考这一问题—要求软件开发团队写出安全的软件。

“千里之堤,溃于蚁穴”,软件中一个极小的失误也将导致整个软件的崩溃。

因此代码安全的时代即将到来:

首先,时代在变,从“WorldWideWeb”(万维网)到“WorldWildWeb”(混乱无序的网)绝非文字游戏。

在如今这个充满了敌意的网络环境里面,编写的代码必须经得起考验,再用旧的思维模式去思考新的问题是非常危险的。

其次,安全的产品同时也是高质量的产品,安全是高质量产品的一个子集。

再次,媒体和竞争对手都喜欢在安全问题上大做文章,这些都是能上头条新闻的信息。

最后,修补安全漏洞的代价是十分高昂的,除了直接的人力和误工等损失之外,还包括改善公共关系和客户信任度的降低的损失,这称之为“商誉”上的损失[1]。

1代码安全存在的问题

1.1重大代码安全问题案例

开发者在软件开发时喜欢加入一些自认为是有益于代码安全的技术,但其所加入的检测技术根本就没有任何安全性而言。

这也就是开发团队认为安全的代码事实上漏洞百出的原因之一。

 

图11失效时进入安全模式

图11中的代码表面看上去很安全,但是当IsAccessAllowed失效时,情况就会很糟糕。

例如:

但这个函数被调用时,系统用完了内存或对象句柄,用户就可以执行有特权的任务,因为这个函数可能返回一个像ERROR_NOT_ENOUGH_MEMORY的错误。

1)AT&T电话网络瘫痪

1990年1月15日下午起的9个小时内,AT&T公司的电话网络一直处于瘫痪的状态[2]。

电话交换采用的是计算机系统,在专家的努力下找到了造成此次电话网络瘫痪的问题代码,见图12。

networkcode()

{

switch(line)

{

caseTHING1:

doit1();

break;

caseTHING2:

if(STUFF==x)

{do_first_stuff();

if(OTHER_STUFF==y)

break;

do_later_stuff();

}

initialize_modes_pointer();//编码者的原意是跳到这里

break;

default:

processing();

}//但事实上跳到了这里,导致//use_modes_pointer未初始化

use_modes_pointer();

}

图12问题代码

2)Sun公司的20,000,000$

1999年的春天,在Sunsoft的操作系统开发小组中,有一个“一级优先”的Bug报告,这个报告是关于异步I/O库的问题。

如果这个Bug不解决,将会使一桩价值2000万美元的硬件生意不能继续,因为客户需要使用这个库的功能。

在专家的努力排查下,把问题锁定在下面这行代码:

x==2上,代码的原意是:

x=2但程序员在写这条语句使不小心多打了一个‘=’。

Sun公司差点就因为那个程序员的疏忽而损失2000万美元[3]。

1.2何谓代码安全

在Internet出现之前,甚至在大型机、终端以及基于它们的应用程序出现以前,很少有人会考虑如何编写安全的代码。

那个时代的应用程序写在纸带上,它们仅仅根据不同的输入按照指定的算法计算出某一项结果。

它们不会长时间的运行,更不会向不同的用户提供服务。

但是,时代变了,如今越来越多的Service程序应运而生(不管是基于Windows还是Unix,Linux),它们总是日复一日地运行,处理源源不断的各种交易请求。

因此,人们很自然的要求那些Service程序能够保证日趋复杂的交易的顺利进行。

这显然要更稳

定,处理能力更大,面对攻击更加坚强,还要有更好的扩展性,以满足“7天*24小时”的要求。

代码安全就是保证这些要求的必要条件之一。

代码安全不是能够被隔离在一个特定代码区域中的东西。

就如同性能、可伸缩性、可操纵性和代码的可读性一样,安全意识是每一个软件设计人员、开发人员和测试人员必须知道的规程。

代码安全也是一种应该普遍拥有的意识。

如同大厦需要安全稳固一样,软件也需要安全稳固,否则随着工程的增大危险也就越发逼近了[4]。

1.3存在代码安全问题的原因

代码存在不安全因素的原因众多,但是归结起来主要包括两个方面:

意识因素和物质因素。

这里的意识与物质不同于哲学的意识与物质,但是其关系极为相似。

意识因素促使程序员在编写底层代码的时候将其错误意识应用于实践,造成代码的安全缺陷;反之亦然。

1)意识因素

科学研究要求研究者坚持唯物主义,但却不能忽视精神因素对物质的反作用。

软件开发者关于代码安全的错误意识将指导其编码,从而造成无法估量的后果。

常见的认识错误有以下几种:

(1)何谓高质量软件

在程序员的意识形态中可靠软件的概念和高质量软件的概念是等价的。

毕竟软件工程的思想认为:

没有完全正确的软件,只有能可靠运行的软件。

然而高质量软件与可靠软件的确是不同的,其关系见图13。

图13高质量软件和安全软件的关系

(2)迷信防火墙

防火墙可以在很大程度上保护用户的计算机免受攻击,但认为配置了防火墙之后,网络就安全了的想法是不对的。

防火墙的局限性表现在以下几个方面:

①防火墙不能防范内部人员的攻击

防火墙只能提供周边保护,并不能控制内部用户对内部网络滥用授权的访问。

内部用户可以窃取数据、破坏硬件和软件,并可巧妙地修改程序而不接近防火墙。

统计表明,由内部引起的网络安全问题约占总数的80%。

②防火墙不能防范绕过它的连接

防火墙可有效地检查由它进行传输的信息,但不能阻止绕过它传输的信息。

比如,如果站点允许对防火墙后面的内部系统进行拨号访问,那么防火墙就没有办法阻止攻击者进行的拨号入侵。

③防火墙不能防御全部威胁

防火墙可以防御已知的威胁。

设计优秀的防火墙理论上应该可以防御新的威胁,但是目前没有任何一款防火墙有能力防御所有的威胁。

④防火墙不能防御恶意程序和病毒

虽然大多数防火墙能扫描所有通过的信息,以决定是否允许他们通过防火墙进入内部网络,但扫描是针对源、目的地址和端口号的,而不是扫描数据的确切内容。

因为在网络上传输二进制文件的编码方式太多,并且有太多的不同结构的病毒,因此防火墙不可能查找所有的病毒,也就不能有效地防范像病毒这类程序的入侵。

如今恶意程序发展迅速,病毒可以依附于共享文档传播,也可通过E-Mail附件的形式在Internet上迅速蔓延。

Web本身就是一个病毒源,许多站点都可以下载病毒程序甚至源码。

某些防火墙可以根据已知病毒和木马的特征码检查数据流,虽然这样做会有些帮助但并不可靠,因为类似的恶意程序的种类很多,有多种手段可使它们在数据中隐藏,防火墙对那些新的病毒和木马程序是无能为力的。

此外,防火墙只能发现从其它网络来的恶意程序,但许多病毒却是通过被感染的移动存储设备或系统直接进入网络的。

所以,防火墙并不是万能的。

(3)否认安全的必要性

一个现实的问题是众多的软件开发者在开发过程中没有把安全问题作为软件创收的一项功能。

开发商甚至认为安全性应该被看作是低劣产品的一项功能,完美的产品是不需要安全性能的、代码的安全性并不是软件开发者必备的重要技巧之一。

正是基于此,开发商不愿意花钱培训程序员以使之能够尽可能的编写安全的代码,也不愿意在安全技术上投资。

在攻击发生以后才认识到安全的重要性,才给产品打补丁确保产品的安全。

古人云:

“亡羊补牢,为时未晚”,但是对于软件开发这种特殊行业来说,的确是晚了一步。

对一个失去生命的生物说对不起没有丝毫作用[5]。

2)物质因素

与万物归于物质类似,任何代码安全问题归根到底可以看作是技术问题。

(1)对软件的运行环境一知半解

不了解软件运行的环境,对其依赖的操作系统一知半解甚至对编写软件所用的语言不甚了解。

例如:

递归是每个程序员必须掌握的思想,但是对于何时才能应用递归思想却不是每个程序员都知道的。

递归只能应用于以下两种情况:

(2)用其它的方法难以描述待解决的问题

(3)运算结果与所求结果存在逆序关系

正是用递归思想来求解斐波那契数列的算法把程序员引向了错误的深渊。

关于递归的第二种用法见图1-4。

 

//问题描述:

把1234转换成‘1’,‘2’,‘3’,‘4’并输出;

//方案:

用取余法得到每一位数+‘0’入栈出栈。

voidint_to_ascii(inti)

{

inttemp=i;

if(temp!

=0)

int_to_ascii(temp/10);

printf(“%c”,temp%10+‘0’);

}

 

图14递归的用法

(4)乱用随机数技术

有些软件需要输入一定的随机数才能使用。

但这就一定能保证这个随机数生成函数产生的是随机数吗?

随机数的产生一般利用库函数:

rand(),rand()的源代码(\安装目录\MicrosoftVisualStudio\VC98\CRT\SRC)见图15。

由源代码可以看出,rand()生成的随机数是有规律的,完全可以根据上次生成的随机数,推算出下一次的随机数。

int__cdeclrand(void)

{

#ifdef_MT

_ptiddataptd=_getptd();

return(((ptd->_holdrand=ptd->_holdrand*214013L

+2531011L)>>16)&0x7fff);

#else

return(((holdrand=holdrand*214013L+2531011L)>>16)&0x7fff);

#endif

}

图15rand()源码

(5)乱用密码技术

大部分开发者认为采用了密码技术的软件产品一定是安全的,所以在任何可能用到密码技术的地方都用上密码技术,但是密码技术不是万能的。

1.4不安全代码造成的后果

一旦代码出现安全问题,软件就会有漏洞。

漏洞(Bug):

顾名思义就是软件中有缺陷、有问题的地方。

漏洞的来源有:

系统设计上的疏忽;应用软件设计上的疏忽;程序设计语言的缺陷;软件底层代码存在不安全因素。

存在漏洞的软件不但容易成为黑客攻击的目标,还可能在运行时崩溃。

能够利用漏洞进行攻击的黑客往往也是编程高手,他们能够利用仅有的提示信息发现系统或软件中有问题的代码进而进行攻击。

目前熟知的攻击、入侵方式大多都是基于漏洞的,并且造成后果比较严重、颇具影响力的网络攻击也是基于漏洞的。

现在的软件好比是一座在某些不为人知的角落里设有开口的建筑,高明的人可以利用某些手段找到这些开口,从而可以不需要出入证就可以进出。

为了避免这种情况,软件开发商为其产品不断的打补丁但却从来没有把所有的开口关闭。

更糟糕的情况是:

为一个开口打的补丁却打开了新的开口(回归性漏洞)。

软件有漏洞才会被黑客利用从而进行攻击行为,根据逆向思维的提示:

攻击者无法攻击一个没有找出漏洞的软件。

“苍蝇不叮无缝的鸡蛋”说的就是这个道理。

虽然做到这一点很难,但与其每天花时间打补丁,倒不如在软件开发之前就注意代码的安全性问题。

安全的代码应该是高质量代码的前提条件,而不是其特性。

目前,软件漏洞的存在形式主要有:

缓冲区溢出、内存泄露、数组下标越界等[6]。

2软件的安全漏洞

要想提高代码的安全性,必须知道造成软件存在漏洞的代码有哪些,因此熟知软件漏洞的分类有易于在编写代码时避免犯相同的错误。

2.1缓冲区溢出

1)漏洞概述

缓冲区溢出是黑客进行攻击以及破解软件的惯用手法。

由于缓冲区是程序在内存中动态分配的,为了不占用太多的内存,一个有动态分配变量的程序在运行时才给变量分配内存空间。

当程序试图把数据放到内存中的某一位置但没有足够的空间时,就会发生缓冲区溢出。

缓冲区溢出程序使用这个溢出的数据将汇编语言代码放到计算机内存的某一位置:

通常是产生超级用户权限的地方。

简单的缓冲区溢出并不会产生太大的安全缺陷,最多造成程序崩溃;把溢出送到能够以超级管理员权限运行命令的区域才是最大的安全缺陷。

最早的缓冲区溢出发生在Unix系统上。

这是因为Unix操作系统是用c语言编写的,而c语言又不进行缓冲区边界检查,故在一定情况下如果用户输入的数据长度超过了应用程序指定的缓冲区的大小,就会覆盖其他的数据区造成程序崩溃或其他不可预知的错误。

目前,利用缓冲区溢出进行的攻击数占攻击总数的一半以上。

例如在c语言中,动态申请内存用的是malloc()函数[7]。

用法见图21。

char*pString;

pString=(char*)malloc(sizeof(char)*10);

 

图21malloc()函数的应用

在上面的代码中malloc()用于分配一段内存空间并返回指向该空间的指针。

有的程员总假想内存足够大,故malloc()总能返回正确的指针。

但是一旦malloc()分配失败,在不进行空指针检测的情况下引用pString就会出现Bug。

可用

图22的代码检查可分配的内存空间。

intMB=0;

while(malloc(1<<20))

++MB;

printf(“系统可分配的内存数是:

%d”,MB);

 

图22可分配的内存数

 

2)缓冲区溢出的分类

缓冲区溢出主要有:

静态缓冲区溢出,堆溢出,格式化字符串,Unicode与ANSI等原因引起的缓冲区溢出。

静态缓冲区溢出和堆溢出上面已提到过,在此就不在介绍。

(1)格式化字符串Bug

严格说来,格式化字符串的Bug并不是缓冲区溢出,但是因为它会导致与缓冲区溢出同样的问题。

这个问题来源于这样一个事实:

对某个参数变量可变的函数,没有任何现实可行的方法来确定到底输入了多少个参数。

造成这一问题的原因是通过%n格式指示符写入的一定数量的字节将被格式字符串写入到参数提供的指针中。

要解决上述问题相对来说比较简单:

在printf系列函数中,始终传递一个格式字符串。

例如:

printf(input)会存在安全漏洞,但printf(“%s”,input)就不会存在安全漏洞。

(2)Unicode和ANSI问题

由于Unicode和ANSI的不匹配而引起的缓冲区溢出在Windows操作平台上是很常见的。

如果一时糊涂,在Unicode缓冲区以字节大小来计算元素数量就会发生缓冲区溢出的问题。

该问题有两个常见的原因:

①WindowsNT及以后的Windows版本都是即支持ANSI也支持Unicode字符串。

②绝大多数Unicode函数是按照宽字符格式而不是按字节大小来计算缓冲区的大小。

实例代码如

BOOLGetInfo(char*szName)

{

WCHARwszName[256];

//convertANSInametoUnicode

MultiByteToWideChar(CP_ACP,0,

szName,-1,

wszName,

sizeof(wszName));

.

.

}

 

图23Unicode和ANSI-1

中间代码的问题在于MultiByteToWideChar函数的最后一个参数。

对于改函数,文档中解释说:

用宽字符来指定由lpWideCharStr参数所指向缓冲区的大小。

此次调用输入的值是sizeof(wszName),这个值是256。

但是因为wszName是一个Unicode字符串,有256个宽字符大小,而一个宽字符是了两个字节,所以sizeof(wszName)的值是512,因此该函数就会认为缓冲区的大小是512个字节,由于wszName位于栈中,所以有可能引起缓冲区溢出。

正确的写法见图2-4。

BOOLGetInfo(char*szName)

{

WCHARwszName[256];

//convertANSInametoUnicode

MultiByteToWideChar(CP_ACP,0,

szName,-1,

wszName,

sizeof(wszName)/sizeof(wszName[0]));

.

.

.

}

图24Unicode和ANSI-2

(3)内存泄露

内存泄漏是指堆栈区内存的泄漏。

堆栈区内存是程序用malloc(),new从堆栈中分配的、大小任意的(内存块的大小可以在程序运行期决定)一块内存,使用完后必须用free(),delete显示释放。

否则,这块内存就不能被再次使用,即这块内存泄漏了。

内存泄漏会导致可用内存的数量逐步减少而造成计算机性能降低。

最糟糕的情况是:

过多的可用内存被分配掉而导致全部或部分设备停止正常工作,或者应用程序崩溃。

特别是当泄露发生在操作系统内部或主要的驱动程序是情况会更加糟糕。

造成内存泄露的原因无外乎重复申请动态内存而不释放以及访问以释放的内存。

具体情况见图25。

structnode

{

intvalue;

structnode*next;

};

voiddeleteList(List&list)

{

node*p=list;

if(p&&p->next)

{

free(p);

p=p->next;

}

}

图25内存泄露代码

 

(4)整数溢出

自从计算机编程出现之后,整数的上溢、下溢及算术溢出(尤其是浮点数错误)就

一直存在。

整数溢出已经成为软件安全的下一个威胁。

此漏洞的核心在于:

把一个数据声明为某种类型以后,其运算结果和人工运算的结果不一致。

当然,也有某些语言实现了变长的整数类型,但是这种实现并不常见,而且这种实现还会带来额外的开销。

对不同语言而言,整数溢出漏洞的表现形式也不相同。

C/C++拥有真正的整数类型;VisualBasic使用Variant的浮点数类型来表示数。

C/C++可能是受影响最大的语言,并且还可能由于整数溢出漏洞而导致缓冲区溢出,甚至攻击者可以执行任意代码。

但是所有的语言都会因为此漏洞而拒绝服务,出现逻辑错误。

由于整数截断所造成的逻辑错误使得NFS中出现一个漏洞,该漏洞可使得任何用户可以以root权限来访问文件。

观察2-6中的代码。

constlongMAX_LEN=0x7fff;

shortlen=strlen(input);

if(len

//dosomething

 

图26整数溢出

上述代码除了整数截断错误之外,当len和MAX_LEN比较时,语言规范告诉我们:

在进行比较前,如果操作数类型不同,则要对数据类型进行向上转换。

因此,实际上上述代码所做的是把len从有符号的16位整数转换为有符号的32位整数。

转换时要想保持原有的值不变,则需要对原来的值进行符号扩展,直到长度和数据类型的值保持一致。

图2-6的转换结果为:

len=0x0100;

(long)len=0x00000100;

或者

len=0xffff;

(long)len=0xffffffff;

这样,如果攻击者构造的len的值超过32K,那么len的值就变成了负值,由于进行的是向上类型转换,符号位不变,所以仍

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 化学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1