Chinaunix首页 | 论坛 | 博客
  • 博客访问: 329512
  • 博文数量: 57
  • 博客积分: 146
  • 博客等级: 入伍新兵
  • 技术积分: 769
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-29 14:57
文章分类
文章存档

2014年(39)

2013年(13)

2012年(5)

我的朋友

分类: C/C++

2014-07-09 14:54:02

一.使用限制操作字节数的替代函数,可预防缓冲区溢出的漏洞。
1.strncpy() instead of strcpy()
2.strncat() instead of strcat()
3.fgets() instead of gets()
4.snprintf() instead of sprintf()

若需要操作的字节数超出字节数限制,这些函数将会截断字符串。另外一些像strncpy的函数不会保证字符串是以NULL字符结尾。 错误代码:未对string_data作判断,若string_data是字符串其长度是否大于sizeof(a)

点击(此处)折叠或打开

  1. char *string_data;
  2. char a[16];
  3. /* ... */
  4. strncpy(a, string_data, sizeof(a))

正确代码:

点击(此处)折叠或打开

  1. #define A_SIZE 16
  2. char *string_data;
  3. char a[A_SIZE];
  4. /* ... */
  5. if (string_data) {
  6. if (strlen(string_data) < sizeof(a)) {
  7. strcpy(a, sizeof(a), string_data);
  8. }
  9. else {
  10. /* handle string too large condition */
  11. }
  12. }
  13. else {
  14. /* handle null string condition */
  15. }

二.不要尝试修改字符串常量
字符串常量存储在只读内存区域,尝试修改字符串常量是未定义行为。
错误代码:

点击(此处)折叠或打开

  1. char *p = "string literal";
  2. p[0] = 'S'
p指向字符串常量地址,是只读内存区域不能修改。

正确代码:

点击(此处)折叠或打开

  1. char a[] = "string literal";
  2. a[0] = 'S'
代码copy字符串常量到数组a中,修改a[0].

三.保证有足够的空间存放字符数据和null终结符
缓冲区若没有足够的空间容纳拷贝的数据会导致缓冲区溢出。
错误代码:

点击(此处)折叠或打开

  1. /* ... */
  2. for (i=0; src[i] && (i < sizeof(dest)); i++) {
  3. dest[i] = src[i];
  4. }
  5. dest[i] = '\0';
  6. /* ... */
数组大小在0到sizeof(dst)-1的范围内,上面代码i的最后等于sizeof(dst),dst[sizeof(dst)]='\0',导致缓冲区溢出。

正确代码:

点击(此处)折叠或打开

  1. /* ... */
  2. for (i=0; src[i] && (i < sizeof(dest)-1); i++) {
  3. dest[i] = src[i];
  4. }
  5. dest[i] = '\0';
  6. /* ... */

四.确保字符串最后都是NULL字符结尾
字符串操作不能确定长度正确null结尾的字符串,会导致缓冲区结束溢出和其他不确定的行为

错误代码:

点击(此处)折叠或打开

  1. char a[16];
  2. strncpy(a, "0123456789abcdef", sizeof(a))

正确代码:

点击(此处)折叠或打开

  1. char *string_data = "0123456789abcdef";
  2. char a[16];
  3. /* ... */
  4. if (string_data) {
  5. if (strlen(string_data) < sizeof(a)) {
  6. strcpy(a, string_data);
  7. }
  8. else {
  9. /* handle string too large condition */
  10. }
  11. }
  12. else {
  13. /* handle null string condition */
  14. }

五.不要从一个无边界的数据源拷贝数据到一个固定大小的数组。
1.gets()函数
错误代码:

点击(此处)折叠或打开

  1. char buf[BUFSIZ];
  2. gets(buf)

根据C99规定,gets函数从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为null值,并由此来结束字符串。
本函数可以无限读取,不会判断上限。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值,为了避免这种情况,我们可以用fgets()来替换gets()。

正确代码:

点击(此处)折叠或打开

  1. char buf[BUFSIZ];
  2. int ch;
  3. char *p;
  4. if (fgets(buf, sizeof(buf), stdin)) {
  5. /* fgets succeeds, scan for newline character */
  6. p = strchr(buf, '\n');
  7. if (p) {
  8. *p = '\0';
  9. }
  10. else {
  11. /* newline not found, flush stdin to end of line */
  12. while (((ch = getchar()) != '\n') && !feof(stdin) && !ferror(stdin) );
  13. }
  14. }
  15. else {
  16. /* fgets failed, handle error */
  17. }

fgets函数从文件指针stream中读取sizeof(buf)个字符,存放以buf为起始地址的空间里,直到读完一行,如果成功则返回buf的指针,否则返回NULL。


2.getchar()函数:
当程序调用getchar时.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCⅡ码,如出错返回-1.

错误代码:

点击(此处)折叠或打开

  1. char buf[BUFSIZ], *p;
  2. int ch;
  3. p = buf;
  4. while ( ((ch = getchar()) != '\n') && !feof(stdin) && !ferror(stdin)) {
  5. *p++ = ch;
  6. }
  7. *p++ = 0
如果getchar一直循环下去,会超出BUFSIZE的范围。

正确代码:

点击(此处)折叠或打开

  1. unsigned char buf[BUFSIZ];
  2. int ch;
  3. int index = 0;
  4. int chars_read = 0;
  5. while ( ( (ch = getchar()) != '\n') && !feof(stdin) && !ferror(stderr) ) {
  6. if (index < BUFSIZ-1) {
  7. buf[index++] = (unsigned char)ch;
  8. }
  9. chars_read++;
  10. } /* end while */
  11. buf[index] = '\0'; /* terminate NTBS */
  12. if (feof(stdin)) {
  13. /* handle EOF */
  14. }
  15. if (ferror(stdin)) {
  16. /* handle error */
  17. }
  18. if (chars_read > index) {
  19. /* handle truncation */
  20. }






阅读(781) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~