c - scanf的宽度规范和scanf_s的区别

标签 c scanf buffer-overflow exploit tr24731

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

此代码将保护我们的程序免受缓冲区溢出攻击。

但是没有 scanf_s,我们可以这样写:

scanf("%9s", a);

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

那么这两种方式的根本区别是什么?

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

最佳答案

scanf_s() 没有被 C99 标准(或以前的标准)描述。

如果您想使用针对 C99(或更早版本)的编译器,请使用 scanf()。 对于 C11 标准scanf_s() 比 scanf() 更难使用,以提高针对缓冲区溢出的安全性。

So what is basically different between two ways?

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

And if scanf's width specification is blocking buffer overflow, why do we call original scanf "unsafe"?

可与scanf 函数一起使用的格式说明符支持显式字段宽度设置,这限制了输入的最大大小并防止缓冲区溢出。但是 scanf() 功能很难使用,因为字段宽度必须被嵌入到格式字符串中(没有办法通过可变参数传递它,因为它可以在 printf 中完成)。 scanf 在这方面确实设计得很差。但是,尽管如此,任何声称 scanf 在字符串缓冲区溢出安全方面无可救药地被破坏的说法都是完全虚假的,而且通常是由懒惰的程序员做出的。

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

因此,综上所述,scanf 的问题在于难以正确安全地使用字符串缓冲区。并且不可能安全地用于算术输入。后者才是真正的问题。前者只是一种不便。

scanf_s 通过可变参数传递字段宽度解决了字符数组情况下的缓冲区溢出问题,这可以在 printf 中完成(在 scanf() 字段宽度必须嵌入到格式字符串中)。此外,字段宽度在 scanf_s 中是强制性的,但在 scanf 中是可选的。

关于c - scanf的宽度规范和scanf_s的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40421378/

相关文章:

c++ - 从 C API 调用的 Lua 脚本的执行时间限制

c - 指针的 scanf 函数不起作用(对于使用指针到指针的矩阵)

从 Activity 实例化 IntentService 时 Android 中的 Java 空指针异常

c - 关于 RISC-V 编译器?

python - Cython 对导入做了什么?

c - 如何在循环中结合使用 scanf (对于非字符或字符串)来获取单个字符

c - Fscanf 段错误

c - 我如何利用缓冲区溢出?

c - OpenAcc 复制输入和复制输出时出错

在堆栈中创建大内存