C中不安全的函数以解决办法汇总
C中不安全的函数以解决办法汇总
C 中⼤多数缓冲区溢出问题可以直接追溯到标准 C 库。最有害的罪魁祸⾸是不进⾏⾃变量检查的、有问题的字符串操作(strcpy、strcat、sprintf 和 gets)。⼀般来讲,像“避免使⽤ strcpy()”和“永远不使⽤ gets()”这样严格的规则接近于这个要求。
这些函数由于设计的时候⽐较淳朴,并没有做任何的越界检测,主要容易"被溢出",只需要多设点检查边界,即安全。
⼀、存在问题的函数及其解决⽅案
函数严重性解决⽅案
gets最危险使⽤ fgets(buf, size, stdin)。这⼏乎总是⼀个⼤问题!
strcpy很危险改为使⽤ strncpy。
strcat很危险改为使⽤ strncat。
sprintf很危险改为使⽤ snprintf,或者使⽤精度说明符。
scanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
sscanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
fscanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
vfscanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
vsprintf很危险改为使⽤ vsnprintf,或者使⽤精度说明符。
vscanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
vsscanf很危险使⽤精度说明符,或⾃⼰进⾏解析。
streadd很危险确保分配的⽬的地参数⼤⼩是源参数⼤⼩的四倍。
strecpy很危险确保分配的⽬的地参数⼤⼩是源参数⼤⼩的四倍。
strtrns危险⼿⼯检查来查看⽬的地⼤⼩是否⾄少与源字符串相等。
realpath 很危险(或稍⼩,取决于实
现)
分配缓冲区⼤⼩为 MAXPATHLEN。同样,⼿⼯检查参数以确保输⼊参数不超过
MAXPATHLEN。
syslog 很危险(或稍⼩,取决于实
现)
在将字符串输⼊传递给该函数之前,将所有字符串输⼊截成合理的⼤⼩。
getopt 很危险(或稍⼩,取决于实
现)
在将字符串输⼊传递给该函数之前,将所有字符串输⼊截成合理的⼤⼩。
getopt_long 很危险(或稍⼩,取决于实
现)
在将字符串输⼊传递给该函数之前,将所有字符串输⼊截成合理的⼤⼩。
getpass 很危险(或稍⼩,取决于实
现)
在将字符串输⼊传递给该函数之前,将所有字符串输⼊截成合理的⼤⼩。
getchar中等危险如果在循环中使⽤该函数,确保检查缓冲区边界。fgetc中等危险如果在循环中使⽤该函数,确保检查缓冲区边界。getc中等危险如果在循环中使⽤该函数,确保检查缓冲区边界。read中等危险如果在循环中使⽤该函数,确保检查缓冲区边界。bcopy低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
fgets低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
fgets低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
memcpy低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
snprintf低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
strccpy低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
strcadd低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
strncpy低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
vsnprintf低危险确保缓冲区⼤⼩与它所说的⼀样⼤。
⼆、另⼀种解决⽅案
如果依然想在⾼版本编辑器中使⽤这些函数,那么可以使⽤⼀下两种⽅法解决:
c++strcpy函数用法2、使⽤提⽰中的_CRT_SECURE_NO_WARNINGS,以下是使⽤⽅法:
a. Project properties->Configuration Properties->C/C++->Preprocessor->Preprocessor Definitions
b. 点击按钮 (...)
c. 输⼊:_CRT_SECURE_NO_WARNINGS。 注:使⽤ "\n" 相隔
三、针对不安全函数及其解决办法的详细描述
今天,编写的程序仍然利⽤这些调⽤,因为从来没有⼈教开发⼈员避免使⽤它们。某些⼈从各处获得某个提⽰,但即使是优秀的开发⼈员也会被这弄糟。他们也许在危险函数的⾃变量上使⽤⾃⼰总结编写的检查,或者错误地推论出使⽤潜在危险的函数在某些特殊情况下是“安全”的。
第 ⼀位公共敌⼈是 gets()。永远不要使⽤ gets()。该函数从标准输⼊读⼊⽤户输⼊的⼀⾏⽂本,它在遇到 EOF 字符或换⾏字符之前,不会停⽌读⼊⽂本。也就是:gets() 根本不执⾏边界检查。因此,使⽤ gets() 总是有可能使任何缓冲区溢出。作为⼀个替代⽅法,可以使⽤⽅法 fgets()。它可以做与 gets() 所做的同样的事情,但它接受⽤来限制读⼊字符数⽬的⼤⼩参数,因此,提供了⼀种防⽌缓冲区溢出的⽅法。例如,不要使⽤以下代码:
void main() { char buf[1024]; gets(buf); }
⽽使⽤以下代码:
#define BUFSIZE 1024 void main() { char buf[BUFSIZE]; fgets(buf, BUFSIZE, stdin); }
但是⾃⼰本地测试了下fgets有⼀个不好的地⽅是会将换⾏符也会读进去,这使得在平常做题时使⼈很反感,所以说如果想要读进字符数组还是使⽤()或者line(),这两个都是安全的函数。
C 编程中的主要陷阱
C 语⾔中⼀些标准函数很有可能使您陷⼊困境。但不是所有函数使⽤都不好。通常,利⽤这些函数之⼀需要任意输⼊传递给该函数。这个列表包括:
strcpy()
strcat()
sprintf()
scanf()
sscanf()
fscanf()
vfscanf()
vsprintf
vscanf()
vsscanf()
streadd()
strecpy()
strtrns()
坏消息是我们推荐,如果有任何可能,避免使⽤这些函数。好消息是,在⼤多数情况下,都有合理的替代⽅法。我们将仔细检查它们中的每⼀个,所以可以看到什么构成了它们的误⽤,以及如何避免它。
1、strcpy()函数将源字符串复制到缓冲区。没有指定要复制字符的具体数⽬。复制字符的数⽬直接取决于源字符串中的数⽬。如果源字符串碰巧来⾃⽤户输⼊,且没有专门限制其⼤⼩,则有可能会陷⼊⼤的⿇烦中!
如果知道⽬的地缓冲区的⼤⼩,则可以添加明确的检查:
if(strlen(src) >= dst_size) {
/* Do something appropriate, such as throw an error. */
}
else {
strcpy(dst, src);
完成同样⽬的的更容易⽅式是使⽤ strncpy() 库例程:
strncpy(dst, src, dst_size-1);
dst[dst_size-1] = '\0'; /* Always do this to be safe! */
如果 src ⽐ dst ⼤,则该函数不会抛出⼀个错误;当达到最⼤尺⼨时,它只是停⽌复制字符。注意上⾯调⽤ strncpy() 中的 -1。如果src ⽐ dst 长,则那给我们留有空间,将⼀个空字符放在 dst 数组的末尾。
当然,可能使⽤ strcpy() 不会带来任何潜在的安全性问题,正如在以下⽰例中所见:
strcpy(buf, "Hello!");
即使这个操作造成 buf 的溢出,但它只是对⼏个字符这样⽽已。由于我们静态地知道那些字符是什么,并且很明显,由于没有危害,所以这⾥⽆须担⼼ ― 当然,除⾮可以⽤其它⽅式覆盖字符串“Hello”所在
的静态存储器。
确保 strcpy() 不会溢出的另⼀种⽅式是,在需要它时就分配空间,确保通过在源字符串上调⽤ strlen() 来分配⾜够的空间。例如:
dst = (char *)malloc(strlen(src));
strcpy(dst, src);
2、strcat()函数⾮常类似于 strcpy(),除了它可以将⼀个字符串合并到缓冲区末尾。它也有⼀个类似的、更安全的替代⽅
法 strncat()。如果可能,使⽤ strncat() ⽽不要使⽤ strcat()。
3、函数 sprintf()和 vsprintf()是⽤来格式化⽂本和将其存⼊缓冲区的通⽤函数。它们可以⽤直接的⽅式模仿 strcpy() ⾏为。换句话说,使⽤ sprintf() 和 vsprintf() 与使⽤ strcpy() ⼀样,都很容易对程序造成缓冲区溢出。例如,考虑以下代码:
void main(int argc, char **argv)
{
char usage[1024];
sprintf(usage, "USAGE: %s -f flag [arg1]\n", argv[0]);
}
我们经常会看到类似上⾯的代码。它看起来没有什 么危害。它创建⼀个知道如何调⽤该程序字符串。那样,可以更改⼆进制的名称,该程序的输出将⾃动反映这个更改。 虽然如此, 该代码有严重的问题。⽂件系统倾向于将任何⽂件的名称限制于特定数⽬的字符。那么,您应该认为如果您的缓冲区⾜够⼤,可以处理可能的最长名称,您的程序会 安全,对吗?只要将 1024 改为对我们的操作系统适合的任何数⽬,就好了吗?但是,不是这样的。通过编写我们⾃⼰的⼩程序来推翻上⾯所说的,可能容易地推翻这个限制:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论