【问题标题】:Difference between scanf's width specification and scanf_sscanf的宽度规格和scanf_s的区别
【发布时间】:2017-03-18 05:03:56
【问题描述】:
scanf_s("%s", a, 10);

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

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

scanf("%9s", a);

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

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

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

【问题讨论】:

    标签: c scanf buffer-overflow exploit tr24731


    【解决方案1】:

    scanf_s() 未在 C99 标准(或以前的标准)中描述。

    如果您想使用面向 C99(或以前)的编译器,请使用 scanf()。 对于C11 Standardscanf_s() 比 scanf() 更难使用,以提高针对buffer overflows 的安全性。

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

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

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

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

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

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

    scanf_s 通过将字段宽度传递给可变参数来解决字符数组情况下的缓冲区溢出问题,就像在printf 中一样(在scanf() 中,字段宽度必须为embedded into format string) .此外,字段宽度在 scanf_s 中是必需的,但在 scanf 中是可选的。

    【讨论】:

    • 谢谢。但是还有一个问题,scanf_s 是否可以避免算术溢出? scanf_s 是如何解决这个问题的?
    • 请注意,C 标准中的 scanf_s() 系列函数不提供针对数字输入的算术溢出(下溢)的保护,与 scanf() 系列函数一样 - 至少,根据C11标准的附件K.3.5.3.2。
    猜你喜欢
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    相关资源
    最近更新 更多