1 为什么gets()函数还在我们的代码中?

好吧,最终还是发生了。我们遇到了一个非常严重,并且非常普遍的缓冲区溢出问题。这个问题造成了非常大的影响,修复这个问题的过程,将会非常艰难,非常 慢,代价非常高。在我看来,可能在这个世界上,会有不少软件产品经理这样问程序员们:“为什么你没有警告过我?”,估计这些被问到的程序员中,有很多都会 直接回答道:“我警告过你了,你什么没有听进去?“

在软件开发的过程中,总是存在一个矛盾:正确的解决问题和快速的解决问题。这个问题在安全领域更加的突出。因此在接下来的几周时间里,我们来聊聊这个矛盾。这个矛盾的如下两个方面,在我们聊的过程中相当的重要:

不管你针对问题的解决方案有多完美,如果没有人使用这个解决方案,都是无用功
    不管是处于什么目的,如果你没有使用完美解决方案,那所有的考虑都是白费功夫。因为你的代码里没有实现该解决方案

让我们从这个看起来非常俗气的例子开始吧:C标准库中的 gets() 函数。 这个函数的定义如下:

char * gets ( char * str );

gets() 函数的形参只有一个指针。它会从标准输入流中读字符到一块连续的内存地址空间中。这块地址空间的开始位置就是指针 str 指向的位置。当在输入流中遇到文件结束符( EOF )或者换行符(n)时,读取操作结束。当读入换行符(n)时,该字符不会被放入那块连续的地址空间中。在读取结束时, gets() 会自动在内存空间的末尾追加一个 NULL 字符。经过上述这些操作,对于程序员来说,这个函数得到的就是从标准输入进来的,以 NULL 字符结尾的C字符串。如果读入的字符流是一整行的话,行尾的换行符将会被舍去。

这个函数方便,也有局限性。 C程序员们经常使用它读取标准输入。下面的代码是一种典型的应用场景:

 代码如下 复制代码

char input[100];
printf("Yes or no?n");
gets(input);
/* and so on… */

在过去的30年里,许多C编程社区的同仁们都已经意识到 gets() 函数不安全,而且在保证接口不变的情况下,也无法被改良。原因也比较直观,这个函数只有一个指针作为参数,该指针指向的内存空间将用于保存读入数据。但是 gets() 函数无法知道它需要使用多大的内存空间。如果在标准输入中读入足够长的,不包含换行符的字符留, gets() 函数肯定会覆盖掉指定的内存区域,而程序员对此无能为力。

此外,除了 gets() 函数缺乏安全性,还有它的小伙伴 fgets() 也有问题。 这个函数的原型如下:

 代码如下 复制代码

char * fgets ( char * str, int num, FILE * stream );

str 是一个指针,指向一块内存区域,读入的数据将会存储到这块内存空间。num 是一个整数,指定了内存空间的大小, stream 是一个文件指针,指定了可以从哪里读取。可能第一眼看过去,你会和我当时一样,觉得前面的那段不安全代码,可以使用 fgets() 函数重写,来避免遇到缓冲区溢出的问题。

 代码如下 复制代码

char input[100];
printf("Yes or no?n");
fgets(input, 100, stdin);
/* and so on… */

不过, gets() 函数和 fgets() 函数有个不同点。fgets() 函数会在遇到换行符时停止,并且其保存到内存中的数据会包含该换行符,而 gets() 函数会排除换行符。因此,就简单的这么重写代码无法实现完全同等的功能。而为了保证代码安全,又实现完全相同的功能,我们就需要检查内存地址中的字符,如 果在结尾有换行符,就将其删除。
因此我们可以用拍脑袋的方式, 得到下面的代码。这段代码既安全,又能保证和 gets() 函数的行为相同。

 代码如下 复制代码

/* This code doesn't work! */
char input[100];
printf("Yes or no?n");
fgets(input, 100, stdin);
char *last = input + strlen(input) – 1;
if (*last == 'n')
      *last = '';
/* and so on… */

可是,虽然代码变复杂了,但是还是存在一个隐藏问题,该问题会导致程序崩溃,或者有安全隐患。当程序执行时,如果标准输入流已经得到了所有可用的字符,但 是还没有遇到文件结束符( EOF), fgets() 函数将会通过将 input[0] 标记为 NULL 字符的形式,直接返回一个 NULL 字符串。此时, strlen(intput) 的返回值为0, 因此导致 last 指针指向 input 数组之前的那个字符。因为不能确定这个字符到底是什么,这段代码的行为将因此无法判断。

做个随堂小练习吧, 请自行修复一下这段代码。 点击这里查看修复方法

在我过去工作过的一家公司里,曾经的经理是一个对安全非常敏感的人,他要求 gets() 函数从所有本地的C库中移除。这个要求,就导致我们经常需要重写从其他地方拿到的代码。所以有下面这段对话,也就不足为奇了。

A:你发给我的那段代码,你看了吗?我们需要重写里面的部分代码,去掉对 gets() 函数的调用
    B:为什么 gets() 函数不能出现在代码中?
    A:<长篇大论的解释>此处忽略5421个字
    B:哈,有意思
    A:如果你需要的话,我们很乐意发给你修改后的代码
    B: 好的,我很乐意,发给我吧。不过现在我能告诉你的是,我们暂时还不能做什么,因为我们只能在客户发现并报告此问题的情况下,才能修改代码。

虽然 gets() 函数早就被公认为不安全的,但是它仍然存在于 C89 和 C99 标准,并最终在 C2011 标准中移除了。但这仅仅是在语言标准中的移除,当我检查自己的一些代码时,发现仍有地方用到了它。而且以我目前对C的了解,更有意思的是,目前在C语言库中,还没有一个安全并且方便的取代 gets() 函数的方法。

各位通读了文章的朋友,能否回答如下几个问题:

在读此文之前,你知道 gets() 函数是不安全的吗?
    你所工作的地方,有限制使用 gets() 函数的相关规定吗?
    你曾经冲写过代码来避免使用 gets() 函数吗?
    关于 gets() 函数,你有什么想了解的吗?

请下周继续关注此讨论。

2 实战:如何解决 gets() 函数的安全问题

2.1 工具链的安全警告

目前GCC默认就会为包含对 gets() 函数调用的代码,报出警告信息。

比如下面的代码:

 代码如下 复制代码
#include<stdio.h>
int main(void)
{
  char c[5];
  gets(c);
  puts(c);
}

就会给出下面的提示信息:

 代码如下 复制代码
gets_warn.c:(.text+0xd): warning: the `gets’ function is dangerous and should not be used.


2.2 安全的gets()实现

C11 标准(ISO/IEC 9899:201x)中, gets() 函数被删除, 引入了新的函数 gets_s().

C11 K.3.5.4.1 The gets_s function

 代码如下 复制代码
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

因为目前GCC中还没有完全实现此标准, 因此 gets_s() 函数尚未包含在目前的GNU 工具链中。Clang里也暂时没有增加对 gets_s 的支持。

所以最通用的做法,可能是自己实现一个。 如下是一种实现方式:

 代码如下 复制代码
char *gets_s(char * str, int num)
{
    if (fgets(str, int, stdin) != 0)
    {
        size_t len = strlen(str);
        if (len > 0 && buffer[len-1] == 'n')
            buffer[len-1] = '';
        return buffer;
    }
    return 0;
}

2.3 C标准库中其他存在安全隐患的函数

除了像 gets() 函数这类,非常不安全的函数外。C语言中因为缺少对数组越界的检查,指针的广泛使用,导致不少函数如果使用不当,容易被***利用, 存在安全隐患。

strcpy : 建议使用 strncpy
    strcat : 建议使用 strncat
    sprintf : 建议使用 snprintf

如果你想自己实现一些字符串操作函数,那么下面这种接口设计值得推荐。即务必要规定好目标地址空间的大小:

size_t foobar(char *dest, size_t buf_size, /* operands here */)

微软在MSDN中也就如何安全的使用C语言标准库接口给出了建议,感兴趣的朋友,可以看看 https://msdn.microsoft.com/en-us/library/bb288454.aspx。

转载于:https://blog.51cto.com/10704527/1763072

gets函数的不安性详解相关推荐

  1. 在python中使用关键字define定义函数_python自定义函数def的应用详解

    这里是三岁,来和大家唠唠自定义函数,这一个神奇的东西,带大家白话玩转自定义函数 自定义函数,编程里面的精髓! def 自定义函数的必要函数:def 使用方法:def 函数名(参数1,参数2,参数-): ...

  2. 函数assert()详解

    函数assert()详解: 断言assert是一个宏,该宏在<assert>中,,当使用assert时候,给他个参数,即一个判读为真的表达式.预处理器产生测试该断言的代码,如果断言不为真, ...

  3. python def函数报错详解_python自定义函数def的应用详解

    这篇文章主要介绍了python自定义函数def的应用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 这里是三岁,来和大家唠唠 ...

  4. PHP函数call_user_func和call_user_func_array详解

    今天在群里面,有个叫lewis的在问call_user_func_array的用法,因为之前一直没有用过,也不能说什么,于是看一下手册,发现是这么写的: call_user_func_array (P ...

  5. 哈希函数(散列函数)详解

    哈希函数(散列函数)详解 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换 ...

  6. php。defined,PHP defined()函数的使用图文详解

    PHP defined()函数的使用图文详解 PHP defined() 函数 例子 定义和用法 defined() 函数检查某常量是否存在. 若常量存在,则返回 true,否则返回 false. 语 ...

  7. python中tile的用法_python3中numpy函数tile的用法详解

    tile函数位于python模块 numpy.lib.shape_base中,他的功能是重复某个数组.比如tile(A,n),功能是将数组A重复n次,构成一个新的数组,我们还是使用具体的例子来说明问题 ...

  8. Delphi Format函数功能及用法详解

    DELPHI中Format函数功能及用法详解 DELPHI中Format函数功能及用法详解function Format(const Format: string; const Args: array ...

  9. python中的json函数_python中装饰器、内置函数、json的详解

    装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 先看简单例子: def run(): time.sleep(1 ...

最新文章

  1. Linq之延迟加载特性
  2. python用中文怎么说-如何实现python设置中文界面?
  3. xx is not in the sudoers file 问题解决
  4. Office文档在线预览/在线编辑解决方案 - 毕升OfficeAPI说明
  5. 微服务的隔离和熔断机制
  6. Docker Daemon和Docker Client关系
  7. 8汉化 netreflector_Reflector下载_.NET Reflector官方中文版下载-华军软件园
  8. 手机安全修改IMEI的方法
  9. 【Multisim】模拟电子技术综合设计实验:正弦波、方波、三角波信号发生器的设计与搭建
  10. 290万人考研:所有的不平凡,从不认命开始
  11. kindle如何设置不闪屏_kindle闪屏怎么解决
  12. [练气期]计算机视觉之从矩阵本质修炼图像几何变换秘籍
  13. 【TWVRP】基于matlab粒子群算法求解带时间窗的车辆路径规划问题(总成本最低)【含Matlab源码 2590期】
  14. GCC 9.4 编译error: catching polymorphic type ‘class std::bad_alloc’ by value [-Werror=catch-value=]
  15. matlab多元回归分析怎么计算,第11讲_matlab多元回归分析
  16. Python math.fabs() 方法
  17. 【DKN】(二)config.py
  18. 利用平台系统运营店铺五大法则
  19. 32位和64位系统支持的最大内存
  20. CGB2109-Day12-用户模块管理

热门文章

  1. 商汤科技总裁张文谈人工智能: 未来10年到20年会有巨大爆发 下一个井喷是AI+教育
  2. 人工智能如何彻底改变全球物流和供应链管理
  3. 利用numpy对已知样本点进行多项式拟合
  4. 论文《城市大脑的定义与建设规范探讨》在IEEE(ICBAIE)发表
  5. 科普|深度解析5G与未来天线技术
  6. 国际基因编辑科技发展报告
  7. 一图分析华为最新AI生态与未来趋势
  8. 年增长率超50%,AI芯片竞争白热化
  9. 你拖后腿了吗?工信部发布前 11 月软件行业经济报告
  10. 如果宁静是 Oracle,万茜、张雨绮、黄圣依是什么?