静态代码安全检查工具是一种能够帮助程序员自动检测出源程序中是否存在安全缺陷的软件。它通过逐行分析程序的源代码,发现软件中潜在的安全漏洞。本文针对 C/C++语言程序设计中容易存在的多种安全问题,分别分析了问题的根源,给出了具体可行的分析及检测方法。最后通过对静态代码安全检查工具优缺点的比较,给出了一些提高安全检查效果的建议。
软件漏洞的出现,除了程序员缺少编写高质量安全程序的意识外,编程语言本身的不安全性也使得程序员更容易在无意中编写出存在安全问题的代码。在众多编程语言中,C/C++语言是目前公认的最容易引起安全问题的语言,黑客往往就利用这些安全问题产生的漏洞来绕过安全策略,以达到网络攻击的目的。针对这种情况,在程序运行前,采用静态代码安全检查工具对源程序进行安全检查是一种很有效的方法。它面对的是问题本身而非征兆,所以有时它比动态监测更有效。
1 C/C++ 语言静态代码安全检查工具
静态代码安全检查工具的工作类似于软件测试中的静态测试。它们之间的不同之处在于软件测试是为了找出软件中的错误,而静态代码安全检查的主要目的是解决软件的安全问题,并以查找软件中容易被黑客利用的漏洞为目标。它的基本工作原理是:从前至后逐行读入源程序代码,定位可能的嫌疑,再逐步进行深入分析,直至得到确定的分析结果,最后根据不同的分析结果,依安全策略对其进行处理并报告处理结果。
2 C/C++ 语言静态代码安全检查原理分析
静态代码安全检查的工作过程是:首先读入不安全函数列表,然后先对欲扫描的源程序进行词法分析。根据不安全函数列表,有些函数会被找出来,并做相应的处理;对于需要进行语法分析的函数再做进一步语法分析,确定这些函数是否会引起安全问题,并做相应的处理。重复此过程直到分析完所有源程序,最后报告结果。
具体地说,针对不同类型的安全问题有以下几个方面的分析处理方法。
2.1 缓冲区溢出问题的解决途径
缓冲区溢出问题是目前软件中存在的最普遍的问题。从目前来看,找出了缓冲区溢出问题也就找出了绝大部分的安全问题。缓冲区溢出的最根本原因就是未检查动态缓冲区边界,当源数据长度超出缓冲区长度时产生溢出。要静态地分析出源程序代码中是否存在此类问题,首先就要计算出缓冲区长度。
针对缓冲区的不同类型,可有以下 4 种方法计算缓冲区长度:
(1) 字符串常量:如“satecode scan”,其缓冲区长度为字符数+ 1。它有两种存在方式,一是直接在函数中使用,另一种是出现在变量定义或赋值语句中。不论哪种都可以通过语法分析回归法计算;
(2) 静态缓冲区:如buf[1024],buf[MAX_len],对于前一种表示方式,可以直接根据 1024 计算缓冲区的大小。对于第 2 种情况,通过检查宏定义、常量定义,一般就可以确定缓冲区的大小;
(3) 动态缓冲区:动态缓冲区可以是通过new 进行分配,也可以通过 alloc、malloc 进行分配。对于前一种分配方法,需要考虑所分配的基类型,然后计算缓冲区长度。对于后一种分配方式,可直接通过表达式计算缓冲区大小;
(4) 指针引用:通过引用指针或数组下标,从而引用预先设好的缓冲区的一部分。对于这种情况,先用以上方法求出基缓冲区的大小,再通过表达式求值计算出其偏移。
除此之外,预填数据方法也可以检测出缓冲区溢出。例如:对于 strcpy (buf1, buf2),在调用前加入以下语句:memset
(buf1,'A',sizeof(buf2))。如果 buf2 比buf1 大,则在调试阶段发生缓冲区溢出。
此方法的特点是对于可能引起缓冲区溢出的函数,在调试阶段(debug),预填满源缓冲区数据,使溢出发生在调试阶段, 避免将不安全因素带到运行期。
具体地把C/C++中可能引起缓冲区溢出的函数分为以下几类,针对不同类的函数分别采用不同的分析与处理。
3.1.1 两个参数的字符串拷贝函数
此类的函数包括 strcpy、_mbscpy、strcat、wcscat 等。其特点是函数有两个参数,从一个参数向另一个参数拷贝字符串,当目标参数缓冲区长度小于源参数缓冲区长度时,发生缓冲区溢出。处理此类函数采用数据流跟踪的方法检查缓冲区长度。
例如下面一段程序:
(1) void transdata(char *str)
(2) {char buffer[24];
(3) strcpy(buffer,str); /*把buf[256] 中的内容拷到buffer[24] 里去*/
(4)
(5) char buf [256];
(6) for(i=0;i<255;i++)/*往buf[256]里写入 255 个M*/
(7) buf[i]='M';
(8) buf[255]=0;
(9) transdata (buf);