美文网首页C语言
C语言-编程中的主要陷阱来源

C语言-编程中的主要陷阱来源

作者: 程序猿编码 | 来源:发表于2020-04-25 20:24 被阅读0次

    C 中大多数缓冲区溢出问题可以直接追溯到标准 C 库。最有害的罪魁祸首是不进行自变量检查的、有问题的字符串操作(strcpy、strcat、sprintf 和 gets)。

    如果说之前所提到的一些问题可能只是影响部分功能的实现,那么缓冲区溢出将可能会造成程序运行终止,被不安全代码攻击等严重问题,因此我们不得不特别重视。

    本专栏文章的主题是,通过防御性编程保护代码不受缓冲区溢出攻击。

    永远不要使用 gets()

    #include <stdio.h>
    
    int main(int argc, char **argv){
    
        char buf[128];
        gets(buf);
    
    }
    

    编译:

    编译时编译器会检查不建议使用"gets"。该函数从标准输入读入用户输入的一行文本,它在遇到 EOF 字符或换行字符之前,不会停止读入文本。也就是:gets() 根本不执行边界检查。因此,使用 gets() 总是有可能使任何缓冲区溢出。

    可以将程序改为:

    #include <stdio.h>
    
    #define BUFSIZE 128
    
    int main(int argc, char **argv){
    
        char buf[BUFSIZE];
        fgets(buf,BUFSIZE,stdin);
    
    }
    

    编译运行:

    作为一个替代方法,可以使用方法 fgets()。它可以做与 gets() 所做的同样的事情,但它接受用来限制读入字符数目的大小参数,因此,提供了一种防止缓冲区溢出的方法。

    C 编程中的主要陷阱

    库函数中还有一些函数也可能造成缓冲区溢出,我们应该尽量避免使用它们。

    strcpy()
    strcat()
    sprintf()
    scanf()
    sscanf()
    fscanf()
    vfscanf()
    vsprintf
    vscanf()
    vsscanf()

    如果有任何可能,避免使用这些函数。在大多数情况下,都有合理的替代方法。我们将仔细检查它们中的每一个,所以可以看到什么构成了它们的误用,以及如何避免它。

    strcpy()函数将源字符串复制到缓冲区。没有指定要复制字符的具体数目。复制字符的数目直接取决于源字符串中的数目。如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会陷入大的麻烦中!

    如果知道目的地缓冲区的大小,则可以添加明确的检查:

    if(strlen(src) >= dst_size) {
    
      ...
    
      }else {
    
      strcpy(dst, src);
    }
    

    或者使用strncpy() 库函数:

    strncpy(dst, src, dst_size-1);
      dst[dst_size-1] = '\0'; /* 这样做是为了安全!*/
    
    

    如果 src 比 dst 大,则该函数不会抛出一个错误;当达到最大尺寸时,它只是停止复制字符。注意上面调用 strncpy() 中的 dst_size-1。如果 src 比 dst 长,则那给我们留有空间,将一个空字符放在 dst 数组的末尾。

    确保 strcpy() 不会溢出的另一种方式是,在需要它时就分配空间,确保通过在源字符串上调用 strlen() 来分配足够的空间:

    dst = (char *)malloc(strlen(src));
      strcpy(dst, src);
    

    strcat()函数非常类似于 strcpy(),除了它可以将一个字符串合并到缓冲区末尾。它也有一个类似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。

    使用 sprintf() 和 vsprintf() 与使用 strcpy() 一样,都很容易对程序造成缓冲区溢出。

    继续, scanf系列的函数也设计得很差。在这种情况下,目的地缓冲区会发生溢出。考虑以下代码:

    #include <stdio.h>
    
    int main(int argc, char **argv){
    
      char buf[256];
      sscanf(argv[0], "%s", &buf);
    
      //sscanf(argv[0], "%255s", &buf);
    
    }
    

    如果输入的字大于 buf 的大小,则有溢出的情况。幸运的是,有一种简便的方法可以解决这个问题。考虑以下代码,它没有安全性方面的薄弱环节。

    就是在百分号和 s 之间的 255 指定了实际存储在变量 buf 中来自 argv[0] 的字符不会超过 255 个。其余匹配的字符将不会被复制。

    总结

    缓冲区溢出造成的危害非常大,可能导致程序运行终止或程序运行异常且难以定位问题。

    "缓冲区溢出"漏洞是一个由来已久的漏洞类型,虽然现代操作系统的编译器,已经可以很大程度的阻止此类型漏洞的出现,但是作为一名C/C++程序员,还是有必要对此类漏洞的原理进行一定了解哈。

    所以缓冲区溢出的原理非常简单,总结起来就是一句话:程序向缓冲区写入了超过缓冲区最大能保存的数据。

    程序猿编码

    欢迎关注公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料。或者回复:进入技术交流群。网盘资料有如下:

    相关文章

      网友评论

        本文标题:C语言-编程中的主要陷阱来源

        本文链接:https://www.haomeiwen.com/subject/ccqlwhtx.html