scanf的宽度规范和scanf_s之间的差异

时间:2016-11-04 11:20:59

标签: c scanf buffer-overflow exploit tr24731

scanf_s("%s", a, 10);

此代码将保护我们的程序免受缓冲区溢出漏洞利用。

没有 scanf_s,我们可以写:

scanf("%9s", a);

我认为这段代码也会阻塞缓冲区溢出。这是真的吗?

那么两种方式之间有什么不同呢?

如果scanf的宽度规范阻止缓冲区溢出,为什么我们称原始scanf“不安全”?

1 个答案:

答案 0 :(得分:3)

C99标准(或之前的标准)未描述

scanf_s()

如果要使用以C99(或之前的)为目标的编译器,请使用scanf()。 对于C11 Standardscanf_s()比scanf()更难使用,以提高buffer overflows的安全性。

  

那么两种方式之间有什么不同呢?

scanf_s()是scanf()的更安全版本。在指定目标的参数之后,必须提供目标的大小。程序在复制之前检查缓冲区是否具有指定的大小,以确保没有覆盖并且不运行恶意代码。在scanf_s()

的情况下,必须传递参数
  

如果scanf的宽度规范阻止缓冲区溢出,为什么我们称之为原始scanf"不安全"?

可与scanf函数一起使用的格式说明符支持显式字段宽度设置,这限制了输入的最大大小并防止缓冲区溢出。但scanf()功能很难使用,因为字段宽度必须为embedded into format string(无法通过可变参数传递它,因为它可以在{{1}中完成})。 scanf确实在这方面设计得很差。但是,任何声称scanf在字符串缓冲区溢出安全性方面无可奈何地被破坏的说法完全是假的,通常由懒惰的程序员做出。

printf的真正问题具有完全不同的性质,即使它也是溢出的。当scanf函数用于将数字的十进制表示转换为算术类型的值时,它不提供算术溢出的保护。如果发生溢出,scanf会产生未定义的行为。因此,在C标准库中执行转换的唯一正确方法是来自scanf()系列的函数。

因此,总结一下上述问题,strto的问题是难以正确安全地使用字符串缓冲区。并且不可能安全地用于算术输入。后者是真正的问题。前者只是给您带来不便。

scanf通过将字段宽度传递给可变参数来解决字符数组中缓冲区溢出的问题,因为它可以在scanf_s中完成(在printf字段宽度已经是scanf())。此外,字段宽度在embedded into format string中是必填字段,但在scanf_s中是可选的。