在我看来,两者都有可能溢出缓冲区。然而,我被建议永远不要使用gets(),但仍然鼓励使用scanf()。
仅仅是因为 scanf() 中允许的格式参数还是有其他原因?
该gets
函数不受缓冲区溢出保护。
使用scanf
格式字符串,您可以定义要从标准输入读取并存储在给定内存缓冲区中的字符串的最大长度。例如,scanf("%10s\n", str);
将读取最多 10 个字符。str
缓冲区应该有 11 个字节来存储 NULL 终止字符。
性能方面,如果您仅用于scanf
解决 的缓冲区溢出问题gets
,则更喜欢使用该fgets
函数。
因为您可以输入比缓冲区大小更多的字符,gets() 会很高兴地允许它。此外,gets() 已被弃用(在 C11 中)。所以与 scanf() 的比较不再有效。此外 scanf() 在处理未格式化的数据时也有其自身的问题。
因此,更好的选择是fgets(),然后根据您的需要对其进行处理。
get() 的名义任务是从流中读取字符串。调用者告诉它在哪里放置传入的字符。但是gets() 不检查缓冲区空间。如果调用者提供了一个指向堆栈的指针,并且输入多于缓冲区空间,gets() 将覆盖堆栈。大多数系统很容易用更大的东西覆盖堆栈中间的现有条目,这也会覆盖相邻的条目。作恶者可以通过在参数字符串中存储正确的二进制模式来修改堆栈上的过程激活记录中的返回地址。这将不会将执行流程转移到它的来源,而是转移到一个特殊的指令序列,该指令序列调用 execv() 以用 shell 替换正在运行的映像。该外壳可以发出命令将病毒的副本拖到系统中。所以 gets() 是不安全的。
在gets
输入格式错误的情况下,无法防止缓冲区溢出。scanf
允许控制读取的数据量。
仍然鼓励使用 scanf()。
在 Google 上快速搜索“scanf security”会得到大约 212k 的结果。第一个是维基百科,它指出
使用
%s
没有长度说明符的占位符本质上是不安全的,并且可用于缓冲区溢出。
所以有足够的关于scanf
网络安全的信息。不同之gets
处在于它scanf
具有安全用途,而使用gets
实际上总是一个坏主意。
因为没有办法防止缓冲区溢出。fgets 更安全,因为指定了最大缓冲区长度。